| name | issue-gate |
| description | Enforce GitHub issue preflight before starting implementation work. Use when beginning a new task to match it against open issues, claim an unstarted match, create a new issue when none matches, and abort only when matching is ambiguous or in-progress work belongs to another actor. |
Issue Gate
Overview
Run issue preflight before any new implementation task. Keep GitHub Issues as the source of truth and return one decision: CREATE, CLAIM, ABORT_IN_PROGRESS, or ABORT_UNCERTAIN.
Workflow
- Prepare inputs:
- repository (
owner/repo)
- actor login
- task title
- task body file path
- Fetch open issues using
gh:
gh api --paginate "/repos/owner/repo/issues?state=open&per_page=100" | jq -s '
add
| [ .[]
| select(.pull_request | not)
| {
number: .number,
title: .title,
body: (.body // ""),
url: .html_url,
labels: [ .labels[]?.name ],
assignees: [ .assignees[]?.login ]
}
]'
- Run qualitative LLM matching using task + open issues and produce
ISSUE_GATE_MATCH_JSON.
- Derive and emit one decision with this contract:
{
"decision": "CREATE|CLAIM|ABORT_IN_PROGRESS|ABORT_UNCERTAIN",
"matched_issue_number": 123,
"reason": "string",
"human_action": "string"
}
- Apply gate behavior:
CREATE: create issue and continue task against the created issue.
CLAIM: ensure actor assignment and labels, then continue task against the claimed issue. If the issue is already assigned to ACTOR, skip re-assigning.
ABORT_IN_PROGRESS: stop task and hand off only when the matched issue is in progress and not assigned to the current actor.
ABORT_UNCERTAIN: stop task and request human triage.
- When creating the PR for the task, reference the issue in the PR description using a closing keyword (for example:
Closes #$ISSUE).
LLM Matching Input (required)
Provide qualitative matching from the runtime LLM with ISSUE_GATE_MATCH_JSON:
{
"classification": "clear|ambiguous|none",
"matched_issue_number": 123,
"reason": "short explanation"
}
Rules:
ISSUE_GATE_MATCH_JSON is required.
- Missing or malformed
ISSUE_GATE_MATCH_JSON returns ABORT_UNCERTAIN.
classification=clear requires a positive integer matched_issue_number.
Decision Mapping
classification=ambiguous -> ABORT_UNCERTAIN.
classification=none -> CREATE.
classification=clear:
- If matched issue is in progress and assigned to someone other than
ACTOR -> ABORT_IN_PROGRESS.
- If matched issue is in progress and assigned to
ACTOR -> CLAIM.
- If matched issue is not started ->
CLAIM.
In-progress signal:
- Issue has label
status:in-progress, or
- Issue has one or more assignees.
Ownership rule:
- If any assignee login equals
ACTOR, treat issue as owned by current actor and continue (CLAIM).
- If issue is in progress and no assignee matches
ACTOR, abort (ABORT_IN_PROGRESS).
GH Commands
- Create issue:
gh api -X POST "/repos/$REPO/issues" -f "title=$TASK_TITLE" -F "body=@$TASK_BODY_FILE"
- Claim issue:
gh api "/repos/$REPO/issues/$ISSUE" --jq '.assignees[]?.login' | grep -Fxq "$ACTOR" || gh api -X POST "/repos/$REPO/issues/$ISSUE/assignees" -f "assignees[]=$ACTOR"
gh api -X POST "/repos/$REPO/issues/$ISSUE/labels" -f "labels[]=status:in-progress" || true
gh api -X DELETE "/repos/$REPO/issues/$ISSUE/labels/status:todo" >/dev/null 2>&1 || true
References
- Matching rubric:
references/match-rubric.md
- Manual Claude usage:
references/claude-usage.md