Pre-flight checks for open-source contributions: is this GitHub issue actually landable?
Runs on your machine from its package; the steps are below.
At most: moves money, runs code or commands, deletes data, or sends messages for you.
Odel charges nothing per call. The publisher may charge for its own service.
Runs locally over stdio
This server isn't hosted — your MCP client launches it from a package registry. Use one of the commands below, or drop the config into your client (e.g. Claude Desktop).
Run
npx -y @reneturcios/greenlight
MCP client config
{
"mcpServers": {
"greenlight": {
"command": "npx",
"args": [
"-y",
"@reneturcios/greenlight"
]
}
}
}Greenlight checks a GitHub issue before you spend hours on it, and tells you in plain words whether your pull request is likely to land.
You find an issue that looks perfect. You code all evening. Then one of these happens:
These are all contribution rituals: unwritten rules a repo expects before an outside pull request counts. Every repo has different ones, and they hide in different places, from CONTRIBUTING files to AGENTS.md house-rules files (plain-language instruction files that tell people and coding agents how to work in that repo). We hit all of these by hand while vetting real issues, so Greenlight automates the checking.
One engine, four plain steps:
One engine, four surfaces:
GO, RISKY, TAKEN, GATED, STALE. Signals: assignees, linked open/closed/merged PRs (timeline + search + comment references), claim-comment heuristics including scoped claims (phrases like "please assign", "working on this", "taking the remaining fallback ask"), partially-addressed detection (merged PRs that reference the issue, maintainer comments like "half addressed ... leaving this open"), issue age and last activity.AGENTS.md, CLAUDE.md), with each gate recording which file its evidence came from (assignment-first, vouch, CLA, DCO, discussion-first, comment-first, collaborators-only, paused unsolicited PRs, external PRs auto-closed by workflow), plus outcome signals where computable.claim, prep, and pr commands (plus matching MCP tools) that run the pipeline after the verdict. All writes are dry-run by default and need a token plus an explicit go flag.A validation corpus of thirteen real cases from the campaign (test/fixtures/cases/, run by test/cases.test.ts) pins every verdict rule to something that actually happened: a taken issue, a weak PR mention, claim-first gates, assignment and vouch gates, a scoped claim, a half-shipped issue, a clean GO, a stale claim, fix-announcement PR links in sibling repos, a duplicate of a completed issue, and paused unsolicited PRs with a close-external-PRs workflow.
npx @reneturcios/greenlight check <issue-url>
Or from source:
npm install
npm run build
Set GITHUB_TOKEN (a classic personal access token, no scopes needed for public repos) to raise the GitHub API rate limit from 60 to 5000 requests per hour. Greenlight caches API responses under ~/.cache/greenlight.
Run the MCP server with npx @reneturcios/greenlight mcp (stdio), or point your agent at the greenlight command with the single argument mcp.
Greenlight is the front door of a four-tool lifecycle for open-source contribution work, all published under the same npm scope and cross-wired:
npx @reneturcios/gatefile extract owner/repo) extracts a repo's contribution gates into a committed contribution-gates.json. Greenlight consumes that file directly: greenlight check <issue-url> --gates-file contribution-gates.json, or automatically when the file sits in the working directory, so gates are answered once and reused instead of re-derived from prose.npx @reneturcios/claimcheck claims owner/repo) watches claimed issues for stale claims and finished fixes parked on forks, the two ways claimed work silently dies.npx @reneturcios/prwatch attention --user you) triages your open PRs by what needs you right now: review threads, failing checks, conflicts, reviewer silence.Each tool is a CLI and an MCP server (<tool> mcp).
# Verdict for one issue
npx @reneturcios/greenlight check https://github.com/batrapulkit/squidbrake/issues/74
# [GO] batrapulkit/squidbrake#74
# Taint: tell the approver when an agent edits its own setup right after reading outside content
# - open, unassigned, no linked PRs, no claim signals, no blocking gates
# Rank a repo's starter issues, GO first (falls back to recent open
# unassigned issues when the repo does not use those labels; --no-fallback to opt out)
npx @reneturcios/greenlight scan PrefectHQ/fastmcp
# Friction score for a repo
npx @reneturcios/greenlight friction triggerdotdev/trigger.dev
# JSON output for scripting
npx @reneturcios/greenlight check <issue-url> --json
Real examples from our vetting:
batrapulkit/squidbrake#74 scores GO: 0 comments, labeled help wanted, no claims, no gates.shadcn-labs/pdfcn#58 scores RISKY (claimed flag): a volunteer asked for assignment the same day we vetted it.langchain-ai/langchain#41185 scores TAKEN (claim race): 3 strong claimants while still "unassigned".PrefectHQ/fastmcp#5718 scores GATED: FastMCP requires assignment or a "prs welcome" label before a PR.triggerdotdev/trigger.dev#5016 scores GATED: unvouched-author PRs are auto-closed, a vouch request goes first.The verdict engine is deterministic (no LLM) and checks, in order:
weak-pr-mention flag and downgrades an otherwise-GO verdict to RISKY. Marked a duplicate of an issue closed as completed: RISKY with the duplicate-of-closed flag (the work already shipped; a still-open duplicate target only adds a duplicate-of-open warning with its URL).claimed flag. A fresh claim scoped to part of the issue ("taking the remaining fallback ask"): RISKY with claimed + partial-claim flags and a reason naming the claimer and the scope, never TAKEN.stale_claim flag. The claimant probably walked away, but nobody knows for sure. Stale scoped claims get the same treatment..github/workflows for close-external-PR automation.comment-mentioned-pr flag ("may already cover part of this issue"). Neither can produce TAKEN; only closing PRs do that. Fix-announcement comments ("/attempt #N" commands or "Submitted fix for ... in " narratives, often linking PRs in sibling repos) get the same downgrade under their own reason quoting the PR URL, with the attempt-linked-pr flag, even when the PR never names the issue. /attempt comments also register as strong claims.partially-addressed is added, an otherwise-GO verdict is capped at RISKY with a reason like "part of this issue already shipped (PR #905, merged); scope your work to what remains". Never TAKEN.Claim detection scans comments for explicit claim phrases, in-progress signals ("fix ready", "PR incoming", "opened a PR"), and soft offers ("happy to fix", "take a look at this one"). Bot authors are ignored, as are issue reporters unless they announce a ready fix. Soft claims now carry their comment date, so the verdict can show how old they are (the weak-claim flag, warning only). Scoped claims ("taking the remaining fallback ask", "claiming this half") are recorded as partial: a fresh partial claim downgrades an otherwise-GO verdict to RISKY with a reason naming the claimer and the scope, never TAKEN. PR references (#NNN) in non-author comments are cross-checked against the PR API: an open referenced PR that mentions the issue downgrades GO to RISKY with the comment-mentioned-pr flag, and a merged one feeds rule 12 above.
One evening, five of twelve claimed issues were already taken. The races were not in the comments: they were in the issue timelines, where GitHub records PRs that reference the issue even when their bodies never say "closes #N". So check now reads the timeline. An open cross-referenced PR caps the verdict at TAKEN with the PR URL and title quoted. A merged one adds a "the issue may already be fixed, verify what shipped" note instead, capped at RISKY, because a merged PR can fix only part of an issue. Also new: emoji-proof fix-announcement matching ("Opened #NNN", "🤖 ..." prefixes), bounty-liveness warnings (dead platforms like Algora are named, unverified bounties are flagged, and bounties never raise a verdict), and a possibly-server-side warning when the issue's quoted error text does not exist anywhere in the repo. The friction command gains one more line when computable: the share of recent merged PRs written by outsiders and the median time to merge, straight from the API.
Friction score starts at 100 and subtracts gate weights (assignment -25, vouch -35, collaborators-only -50, paused unsolicited PRs -40, external PRs auto-closed -50, discussion-first -10, claim-first -5, CLA/DCO -5 each), adjusts for external PR merge rate and review/response times when computable, and adds up to +10 for open good-first-issues. Unknown signals stay null and are skipped, never guessed. See src/friction.ts for the exact formula.
The same engine is exposed over stdio for coding agents (Claude, Cursor, Cline). The wedge: agents waste the most tokens fixing already-taken issues. Have the agent pre-flight the issue before writing code.
{
"mcpServers": {
"greenlight": {
"command": "npx",
"args": ["-y", "@reneturcios/greenlight", "mcp"],
"env": { "GITHUB_TOKEN": "your-token" }
}
}
}
Tools:
check_issue - verdict for one issue URLscan_repo - rank a repo's open issues, GO first (label-tagged starter issues, falling back to recent open unassigned issues)repo_friction - friction score for a repoclaim_issue - verdict-gated claim comment (dry run unless execute: true)prep_issue - fork and branch check plus a local PREP.md checklist with the repo's learned conventions (dry run unless execute: true)open_pr - DCO-aware PR opening from a fork branch (dry run unless execute: true)Run it locally: npm run dev (MCP entry is src/index.ts; CLI is src/cli.ts).
Greenlight 0.2.0 automates the contribution pipeline its author ran by hand for four real PRs (shadcn-labs/pdfcn #92-#95): verdict, claim comment, fork branch, and opening the PR, with DCO awareness throughout.
# 1. Claim the issue: verdict first, comment shaped by the repo's gates
greenlight claim https://github.com/shadcn-labs/pdfcn/issues/65
# 2. Prepare: fork/branch check (learning the repo's branch convention) plus a PREP.md checklist
greenlight prep https://github.com/shadcn-labs/pdfcn/issues/65 --dir /tmp/prep65
# 3. Open the PR from your fork branch (verifies DCO sign-off on DCO repos)
greenlight pr https://github.com/shadcn-labs/pdfcn/issues/65 --branch feat/quarterly-report-block
Safety defaults, and this is a feature:
--yes
(CLI) or execute: true (MCP).GITHUB_TOKEN (or GH_TOKEN); without one they print a clear
error naming the env var and exit non-zero.claim refuses TAKEN or STALE verdicts unless
--force, and refuses vouch-gated repos outright (a vouch cannot be
automated). Assignment-gated repos get an assignment request instead of
an intent comment; claim-first repos (comment before starting) get the
standard intent comment, which satisfies the ritual.prep reads the head branches of recent
closed PRs and follows a dominant convention (pdfcn's feat/<slug>-block)
while still showing the feat/<slug>-<number> default.pr verifies every commit on the branch
carries a Signed-off-by: line and refuses, listing the unsigned
commits, when one is missing.prep also learns the repo's contribution rituals
for the PREP.md checklist: which house-rules files exist, the verify
command they insist on (like pnpm verify), whether the repo assembles
its changelog from a .changes/ directory, which root package.json
scripts exist, and whether recent commits follow Conventional Commits.
Binding rules increasingly live in AGENTS.md rather than CONTRIBUTING,
and prep reads those too.data/friction-index.json is a checked-in, growing dataset of scored repos. It starts with the MCP/AI ecosystem we hand-vetted on 2026-10-13 (FastMCP, trigger.dev, langchain, deepagents, openclaw, squidbrake, reticle, pdfcn, chatflow-agent, and the three MCP SDK repos). Regenerate it with npm run index.
Entries labeled hand-verified 2026-10-13 come from reading the repos' actual policies and issue trackers by hand. Entries labeled live were parsed from live house-rules files (CONTRIBUTING variants, AGENTS.md, CLAUDE.md). Each gate records which file its evidence came from. Computed outcome fields (merge rates, review times) stay null until we can compute them honestly, never fabricated.
npm test # tsx --test, includes fixture tests that reproduce our real verdicts
npm run build
MIT. See LICENSE.