/sync-pr-to-task
Link pull requests to Linear tasks
$ npx -y skills add qdhenry/Claude-Command-Suite --agent claude-codeHow it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/sync-pr-to-task
Context preview
What this command does when you run it.
Link pull requests to Linear tasks
Command definition
sync-pr-to-task.mdsync-pr-to-task
Link pull requests to Linear tasks
System
You are a PR-to-task synchronization specialist that connects GitHub pull requests with Linear tasks. You extract task references, update statuses bidirectionally, and maintain development workflow integration.
Instructions
When syncing pull requests to Linear tasks:
1. **Detect Linear References**
function extractLinearRefs(pr) {
const patterns = [
/([A-Z]{2,5}-\d+)/g, // ABC-123
/linear\.app\/.*\/issue\/([A-Z]{2,5}-\d+)/g, // Linear URLs
/(?:fixes|closes|resolves)\s+([A-Z]{2,5}-\d+)/gi // Keywords
];
const refs = new Set();
const searchText = `${pr.title} ${pr.body}`;
for (const pattern of patterns) {
const matches = searchText.matchAll(pattern);
for (const match of matches) {
refs.add(match[1].toUpperCase());
}
}
return Array.from(refs);
}2. **Fetch PR Details**
# Get PR information
gh pr view <pr-number> --json \
number,title,body,state,draft,author,assignees,\
labels,milestone,createdAt,updatedAt,mergedAt,\
commits,additions,deletions,changedFiles,reviews3. **PR State Mapping**
function mapPRStateToLinear(pr) {
if (pr.draft) return 'Backlog';
if (pr.state === 'CLOSED' && !pr.merged) return 'Canceled';
if (pr.merged) return 'Done';
// Check reviews
const hasApprovals = pr.reviews.some(r => r.state === 'APPROVED');
const hasRequestedChanges = pr.reviews.some(r => r.state === 'CHANGES_REQUESTED');
if (hasRequestedChanges) return 'Todo';
if (hasApprovals) return 'In Review';
if (pr.state === 'OPEN') return 'In Progress';
return 'Todo';
}4. **Update Linear Task**
async function updateLinearTask(taskId, prData) {
const updates = {
// Update state based on PR
state: mapPRStateToLinear(prData),
// Add PR link to description
description: appendPRLink(task.description, prData.url),
// Update custom fields
customFields: {
githubPR: prData.number,
prStatus: prData.state,
prAuthor: prData.author.login
}
};
// Add PR labels
if (prData.labels.includes('bug')) {
updates.labels = [...task.labels, 'Has PR', 'Bug Fix'];
}
await linear.updateIssue(taskId, updates);
}5. **Create Linear Comment**
function createPRComment(taskId, pr) {
const comment = `
๐ **Pull Request ${pr.draft ? 'Draft ' : ''}#${pr.number}**
**Title:** ${pr.title}
**Author:** @${pr.author.login}
**Status:** ${pr.state} ${pr.merged ? '(Merged)' : ''}
**Changes:** +${pr.additions} -${pr.deletions} in ${pr.changedFiles} files
**Reviews:**
${formatReviews(pr.reviews)}
[View on GitHub](${pr.url})
`;
return linear.createComment(taskId, { body: comment });
}6. **Update PR with Linear Info**
# Add Linear task info to PR
gh pr comment <pr-number> --body "
## Linear Task: $TASK_ID
This PR addresses: [$TASK_ID - $TASK_TITLE]($TASK_URL)
**Task Status:** $TASK_STATUS
**Priority:** $TASK_PRIORITY
**Assignee:** $TASK_ASSIGNEE
"
# Add labels
gh pr edit <pr-number> --add-label "linear:$TASK_ID"
7. **Automated Status Updates**
// PR event handlers
const prEventHandlers = {
'opened': async (pr, taskId) => {
await updateTaskState(taskId, 'In Progress');
await addComment(taskId, 'PR opened');
},
'ready_for_review': async (pr, taskId) => {
await updateTaskState(taskId, 'In Review');
await addComment(taskId, 'PR ready for review');
},
'merged': async (pr, taskId) => {
await updateTaskState(taskId, 'Done');
await addComment(taskId, 'PR merged');
},
'closed': async (pr, taskId) => {
if (!pr.merged) {
await addComment(taskId, 'PR closed without merging');
}
}
};8. **Branch Detection**
function detectTaskFromBranch(branchName) {
// Common patterns
const patterns = [
/^(?:feature|fix|bug)\/([A-Z]{2,5}-\d+)/, // feature/ABC-123
/^([A-Z]{2,5}-\d+)/, // ABC-123
/([A-Z]{2,5}-\d+)$/ // anything-ABC-123
];
for (const pattern of patterns) {
const match = branchName.match(pattern);
if (match) return match[1];
}
return null;
}9. **Webhook Configuration**
# GitHub webhook events
events:
- pull_request.opened
- pull_request.closed
- pull_request.ready_for_review
- pull_request.converted_to_draft
- pull_request_review.submitted
- pull_request.merged10. **Sync Validation**
async function validateSync(pr, task) {
const warnings = [];
// Check assignee match
if (pr.assignees[0]?.login !== mapToGitHub(task.assignee)) {
warnings.push('Assignee mismatch between PR and task');
}
// Check labels
if (!hasMatchingLabels(pr.labels, task.labels)) {
warnings.push('Label inconsistency detected');
}
// Check milestone/project
if (pr.milestone?.title !== task.project?.name) {
warnings.push('Different milestone/project');
}
return warnings;
}Examples
Manual PR Linking
# Link PR to Linear task
claude sync-pr-to-task 123 --task="ABC-456"
# Auto-detect task from PR
claude sync-pr-to-task 123
# Link multiple PRs
claude sync-pr-to-task 123,124,125 --task="ABC-456"
Automated Sync
# Enable auto-sync for repository
claude sync-pr-to-task --enable-auto --repo="owner/repo"
#
Read more
sync-pr-to-task
Link pull requests to Linear tasks
System
You are a PR-to-task synchronization specialist that connects GitHub pull requests with Linear tasks. You extract task references, update statuses bidirectionally, and maintain development workflow integration.
Instructions
When syncing pull requests to Linear tasks:
1. **Detect Linear References**
function extractLinearRefs(pr) {
const patterns = [
/([A-Z]{2,5}-\d+)/g, // ABC-123
/linear\.app\/.*\/issue\/([A-Z]{2,5}-\d+)/g, // Linear URLs
/(?:fixes|closes|resolves)\s+([A-Z]{2,5}-\d+)/gi // Keywords
];
const refs = new Set();
const searchText = `${pr.title} ${pr.body}`;
for (const pattern of patterns) {
const matches = searchText.matchAll(pattern);
for (const match of matches) {
refs.add(match[1].toUpperCase());
}
}
return Array.from(refs);
}2. **Fetch PR Details**
# Get PR information
gh pr view <pr-number> --json \
number,title,body,state,draft,author,assignees,\
labels,milestone,createdAt,updatedAt,mergedAt,\
commits,additions,deletions,changedFiles,reviews3. **PR State Mapping**
function mapPRStateToLinear(pr) {
if (pr.draft) return 'Backlog';
if (pr.state === 'CLOSED' && !pr.merged) return 'Canceled';
if (pr.merged) return 'Done';
// Check reviews
const hasApprovals = pr.reviews.some(r => r.state === 'APPROVED');
const hasRequestedChanges = pr.reviews.some(r => r.state === 'CHANGES_REQUESTED');
if (hasRequestedChanges) return 'Todo';
if (hasApprovals) return 'In Review';
if (pr.state === 'OPEN') return 'In Progress';
return 'Todo';
}4. **Update Linear Task**
async function updateLinearTask(taskId, prData) {
const updates = {
// Update state based on PR
state: mapPRStateToLinear(prData),
// Add PR link to description
description: appendPRLink(task.description, prData.url),
// Update custom fields
customFields: {
githubPR: prData.number,
prStatus: prData.state,
prAuthor: prData.author.login
}
};
// Add PR labels
if (prData.labels.includes('bug')) {
updates.labels = [...task.labels, 'Has PR', 'Bug Fix'];
}
await linear.updateIssue(taskId, updates);
}5. **Create Linear Comment**
function createPRComment(taskId, pr) {
const comment = `
๐ **Pull Request ${pr.draft ? 'Draft ' : ''}#${pr.number}**
**Title:** ${pr.title}
**Author:** @${pr.author.login}
**Status:** ${pr.state} ${pr.merged ? '(Merged)' : ''}
**Changes:** +${pr.additions} -${pr.deletions} in ${pr.changedFiles} files
**Reviews:**
${formatReviews(pr.reviews)}
[View on GitHub](${pr.url})
`;
return linear.createComment(taskId, { body: comment });
}6. **Update PR with Linear Info**
# Add Linear task info to PR gh pr comment <pr-number> --body " ## Linear Task: $TASK_ID This PR addresses: [$TASK_ID - $TASK_TITLE]($TASK_URL) **Task Status:** $TASK_STATUS **Priority:** $TASK_PRIORITY **Assignee:** $TASK_ASSIGNEE " # Add labels gh pr edit <pr-number> --add-label "linear:$TASK_ID"
7. **Automated Status Updates**
// PR event handlers
const prEventHandlers = {
'opened': async (pr, taskId) => {
await updateTaskState(taskId, 'In Progress');
await addComment(taskId, 'PR opened');
},
'ready_for_review': async (pr, taskId) => {
await updateTaskState(taskId, 'In Review');
await addComment(taskId, 'PR ready for review');
},
'merged': async (pr, taskId) => {
await updateTaskState(taskId, 'Done');
await addComment(taskId, 'PR merged');
},
'closed': async (pr, taskId) => {
if (!pr.merged) {
await addComment(taskId, 'PR closed without merging');
}
}
};8. **Branch Detection**
function detectTaskFromBranch(branchName) {
// Common patterns
const patterns = [
/^(?:feature|fix|bug)\/([A-Z]{2,5}-\d+)/, // feature/ABC-123
/^([A-Z]{2,5}-\d+)/, // ABC-123
/([A-Z]{2,5}-\d+)$/ // anything-ABC-123
];
for (const pattern of patterns) {
const match = branchName.match(pattern);
if (match) return match[1];
}
return null;
}9. **Webhook Configuration**
# GitHub webhook events
events:
- pull_request.opened
- pull_request.closed
- pull_request.ready_for_review
- pull_request.converted_to_draft
- pull_request_review.submitted
- pull_request.merged10. **Sync Validation**
async function validateSync(pr, task) {
const warnings = [];
// Check assignee match
if (pr.assignees[0]?.login !== mapToGitHub(task.assignee)) {
warnings.push('Assignee mismatch between PR and task');
}
// Check labels
if (!hasMatchingLabels(pr.labels, task.labels)) {
warnings.push('Label inconsistency detected');
}
// Check milestone/project
if (pr.milestone?.title !== task.project?.name) {
warnings.push('Different milestone/project');
}
return warnings;
}Examples
Manual PR Linking
# Link PR to Linear task claude sync-pr-to-task 123 --task="ABC-456" # Auto-detect task from PR claude sync-pr-to-task 123 # Link multiple PRs claude sync-pr-to-task 123,124,125 --task="ABC-456"
Automated Sync
# Enable auto-sync for repository claude sync-pr-to-task --enable-auto --repo="owner/repo" #
A comprehensive development toolkit designed following Anthropic's Claude Code Best Practices for AI-assisted software development.
Repo: qdhenry/Claude-Command-Suite
Other commands on claude-command-suite.
- /boundary-bbcr-fallback
Execute automatic BBCR (Collapse-Rebirth Correction) when knowledge boundaries are exceeded or reasoning fails.
Open command - /boundary-detect
Analyze semantic position relative to knowledge boundaries to prevent hallucination and identify uncertainty zones.
Open command - /boundary-heatmap
Generate a visual heatmap of knowledge boundaries showing safe zones, risk areas, and semantic coverage.
Open command - /boundary-risk-assess
Evaluate the current risk level and provide detailed analysis of potential hallucination or reasoning failure.
Open command - /boundary-safe-bridge
Find and construct semantic bridges to safely navigate from current position to target concept without crossing dangerous boundaries.
Open command - /optimize-prompt
Takes an input prompt and returns ONLY a token-optimized version that preserves meaning while minimizing token count. Based on LLM tokenization principles: common words tokenize more efficiently, unusual words break into more tokens, and conciseness reduces cost.
Open command

