From jira
Find suitable JIRA tickets from the backlog to work on based on priority and activity
How this command is triggered — by the user, by Claude, or both
Slash command
/jira:backlog [project-key] [--assignee username] [--days-inactive N]Files this command reads when invoked
The summary Claude sees in its command listing — used to decide when to auto-load this command
## Name jira:backlog ## Synopsis ## Description The `jira:backlog` command helps identify suitable tickets from the JIRA backlog to work on by **intelligently analyzing** unassigned tickets and bot-assigned tickets. Unlike simple filtering, this command reads ticket descriptions, comments, and activity patterns to recommend the best candidates for work. **Key Feature:** The command selects **2 tickets from each priority level** (Critical, High, Normal, Low) that are **actually available to pick up** (unassigned or assigned to bots only), giving you a balanced view across all priorities...
jira:backlog
/jira:backlog [project-key] [--assignee username] [--days-inactive N]
The jira:backlog command helps identify suitable tickets from the JIRA backlog to work on by intelligently analyzing unassigned tickets and bot-assigned tickets. Unlike simple filtering, this command reads ticket descriptions, comments, and activity patterns to recommend the best candidates for work.
Key Feature: The command selects 2 tickets from each priority level (Critical, High, Normal, Low) that are actually available to pick up (unassigned or assigned to bots only), giving you a balanced view across all priorities so you can choose based on your expertise and preference.
Important: This command only recommends tickets that are unassigned or assigned to bots (like "OCP DocsBot"). Tickets assigned to real people are excluded, even if they have no recent activity, because they may already be claimed by someone.
This command is particularly useful for:
How it works:
This command requires JIRA credentials to be configured via the JIRA MCP server setup, even though it uses direct API calls instead of MCP commands.
If you haven't already installed the Jira plugin, see the Jira Plugin README for installation instructions.
⚠️ Important: While this command does NOT use MCP commands to query JIRA, it DOES read credentials from the MCP server configuration file. You must configure the MCP server settings even if you're only using this command.
Why not use MCP commands? The MCP approach has performance issues when fetching large datasets:
Solution: This command uses curl to fetch data directly from JIRA and save to disk, then processes it with Python. It reads JIRA credentials from ~/.config/claude-code/mcp.json - the same file used by the MCP server.
Required Configuration File Format:
Create or edit ~/.config/claude-code/mcp.json:
{
"mcpServers": {
"atlassian": {
"command": "npx",
"args": ["mcp-atlassian"],
"env": {
"JIRA_URL": "https://redhat.atlassian.net",
"JIRA_USERNAME": "[email protected]",
"JIRA_API_TOKEN": "your-atlassian-api-token-here"
}
}
}
}
Field Descriptions:
JIRA_URL: Your JIRA instance URL (e.g., https://redhat.atlassian.net)JIRA_USERNAME: Your Atlassian account email addressJIRA_API_TOKEN: Atlassian API token from Atlassian API Token Management Page⚠️ Recommended Setup: Use the podman containerized approach. We tested npx methods on October 31, 2025, and encountered 404 errors and missing dependencies. The containerized setup works reliably.
Steps:
First, ensure your ~/.config/claude-code/mcp.json is created with credentials (see example above)
Start the MCP server container using credentials from mcp.json:
# Extract credentials from your mcp.json file
JIRA_URL=$(jq -r '.mcpServers.atlassian.env.JIRA_URL' ~/.config/claude-code/mcp.json)
JIRA_USERNAME=$(jq -r '.mcpServers.atlassian.env.JIRA_USERNAME' ~/.config/claude-code/mcp.json)
JIRA_API_TOKEN=$(jq -r '.mcpServers.atlassian.env.JIRA_API_TOKEN' ~/.config/claude-code/mcp.json)
# Start the container
podman run -d --name mcp-atlassian -p 8080:8080 \
-e "JIRA_URL=${JIRA_URL}" \
-e "JIRA_USERNAME=${JIRA_USERNAME}" \
-e "JIRA_API_TOKEN=${JIRA_API_TOKEN}" \
ghcr.io/sooperset/mcp-atlassian:latest --transport sse --port 8080 -vv
Verify the container is running:
podman ps | grep mcp-atlassian
Restart Claude Code to ensure it reads the mcp.json configuration
Managing the Container:
# Check if container is running
podman ps | grep mcp-atlassian
# View logs
podman logs mcp-atlassian
# Stop the container
podman stop mcp-atlassian
# Start the container again
podman start mcp-atlassian
# Remove the container (you'll need to run 'podman run' again)
podman rm mcp-atlassian
To verify your MCP server is configured and can connect to JIRA, you can test it with a simple JIRA query in Claude Code:
Ask Claude Code to run: "Use the mcp__atlassian__jira_get_issue tool to fetch OCPBUGS-1"
If the MCP server is configured and connected, you should see issue details returned. If you see an error:
claude mcp add command.JIRA_API_TOKEN and JIRA_USERNAME are correct.podman ps).See the full JIRA Plugin README for complete setup instructions and troubleshooting.
The command executes the following workflow:
Extract Credentials from MCP Configuration File
~/.config/claude-code/mcp.jsonatlassian MCP server configuration:
MCP_CONFIG="$HOME/.config/claude-code/mcp.json"
JIRA_URL=$(jq -r '.mcpServers.atlassian.env.JIRA_URL' "$MCP_CONFIG")
JIRA_USERNAME=$(jq -r '.mcpServers.atlassian.env.JIRA_USERNAME' "$MCP_CONFIG")
JIRA_API_TOKEN=$(jq -r '.mcpServers.atlassian.env.JIRA_API_TOKEN' "$MCP_CONFIG")
AUTH_TOKEN="$JIRA_API_TOKEN"
Error: JIRA credentials not configured.
This command requires JIRA credentials from the MCP server configuration file.
Please create or edit ~/.config/claude-code/mcp.json with your JIRA credentials.
See Prerequisites section for the required mcp.json format and setup instructions.
Parse Arguments and Set Defaults
mkdir -p .work/jira-backlog/{project-key}/Construct JQL Query
project = {project-key}
AND status NOT IN (Closed, Resolved, Done, Verified, Release Pending, ON_QA)
AND (
assignee IS EMPTY
OR updated <= -{days-inactive}d
)
ORDER BY priority DESC, updated ASC
AND assignee = {username} AND updated <= -{days-inactive}dFetch All Backlog Tickets Using curl with Pagination
Fetch Strategy:
maxResults value)startAt parameter) to fetch all ticketsAuthentication:
JIRA_USERNAME:JIRA_API_TOKEN (base64-encoded) for Atlassian CloudImportant API Details:
/rest/api/3/search/jql endpoint with a JSON body containing jql, fields, and maxResultsAuthorization: Basic <base64(username:token)> header for authenticationBatch Processing Loop:
START_AT=0
BATCH_NUM=0
TOTAL_FETCHED=0
while true; do
# Construct API URL for POST search
API_URL="${JIRA_URL}/rest/api/3/search/jql"
# Build JSON body for POST request
JSON_BODY=$(jq -n \
--arg jql "$JQL" \
--argjson startAt "$START_AT" \
--argjson maxResults 1000 \
'{jql: $jql, startAt: $startAt, maxResults: $maxResults, fields: ["summary","status","priority","assignee","reporter","created","updated","description","labels","components","watches","comment"]}')
# Fetch batch using curl with Basic authentication (POST)
AUTH_HEADER=$(printf '%s:%s' "$JIRA_USERNAME" "$AUTH_TOKEN" | base64 | tr -d '\n')
HTTP_CODE=$(curl -s -w "%{http_code}" \
-X POST \
-o "batch-${BATCH_NUM}.json" \
-H "Authorization: Basic ${AUTH_HEADER}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d "$JSON_BODY" \
"${API_URL}")
# Check HTTP response code
if [ "$HTTP_CODE" -ne 200 ]; then
echo "Error: HTTP $HTTP_CODE received"
cat "batch-${BATCH_NUM}.json"
exit 1
fi
# Parse response to check if more results exist
BATCH_SIZE=$(jq '.issues | length' "batch-${BATCH_NUM}.json")
TOTAL=$(jq '.total' "batch-${BATCH_NUM}.json")
TOTAL_FETCHED=$((TOTAL_FETCHED + BATCH_SIZE))
echo "✓ Fetched ${BATCH_SIZE} tickets (${TOTAL_FETCHED}/${TOTAL} total)"
# Check if done
if [ ${TOTAL_FETCHED} -ge ${TOTAL} ] || [ ${BATCH_SIZE} -eq 0 ]; then
break
fi
# Move to next batch
START_AT=$((START_AT + 1000))
BATCH_NUM=$((BATCH_NUM + 1))
done
echo ""
echo "✓ Fetching complete: ${TOTAL_FETCHED} tickets downloaded in $((BATCH_NUM + 1)) batch(es)"
Why curl instead of MCP:
Process Batches with Python to Filter and Group by Priority
Create a Python script (.work/jira-backlog/{project-key}/process_batches.py) that:
Inputs:
.work/jira-backlog/{project-key}/batch-*.jsonProcessing Logic:
import json
import glob
from collections import defaultdict
# Load all batches
all_tickets = []
for batch_file in sorted(glob.glob('.work/jira-backlog/{project-key}/batch-*.json')):
with open(batch_file) as f:
data = json.load(f)
all_tickets.extend(data['issues'])
# Filter for available tickets
available_tickets = []
for ticket in all_tickets:
assignee = ticket['fields'].get('assignee')
# Include if unassigned
if assignee is None:
available_tickets.append(ticket)
continue
# Include if assigned to a bot
assignee_name = assignee.get('displayName', '').lower()
if 'bot' in assignee_name:
available_tickets.append(ticket)
continue
# Otherwise exclude (assigned to real person)
# Group by priority
priority_buckets = defaultdict(list)
for ticket in available_tickets:
priority_name = ticket['fields']['priority']['name']
# Normalize priority names
if priority_name in ['Critical', 'Blocker']:
priority_buckets['Critical'].append(ticket)
elif priority_name in ['High', 'Major']:
priority_buckets['High'].append(ticket)
elif priority_name in ['Normal', 'Medium']:
priority_buckets['Normal'].append(ticket)
elif priority_name in ['Low', 'Minor', 'Trivial']:
priority_buckets['Low'].append(ticket)
# Save filtered results
with open('.work/jira-backlog/{project-key}/filtered.json', 'w') as f:
json.dump(priority_buckets, f, indent=2)
# Save statistics
stats = {p: len(tickets) for p, tickets in priority_buckets.items()}
with open('.work/jira-backlog/{project-key}/stats.json', 'w') as f:
json.dump(stats, f, indent=2)
print(f"Filtered {len(available_tickets)} available tickets from {len(all_tickets)} total")
print(f"Priority distribution: {stats}")
Outputs:
.work/jira-backlog/{project-key}/filtered.json - All filtered tickets grouped by priority
.work/jira-backlog/{project-key}/stats.json - Priority distribution statistics
Run the script:
python .work/jira-backlog/${PROJECT_KEY}/process_batches.py
Intelligently Analyze and Select Best Tickets from Each Priority
CRITICAL: This is NOT a mechanical selection process. You must read and analyze ticket content to make intelligent decisions.
Load Filtered Data:
.work/jira-backlog/{project-key}/filtered.jsonFor each priority level (Critical, High, Normal, Low):
Step 6a: Extract Tickets for Human-Readable Analysis
Step 6b: Analyze Ticket Suitability Read the formatted data and evaluate each ticket for:
Age Classifications (consider when prioritizing):
Disqualifying Factors (skip these tickets):
Positive Indicators (prioritize these):
Step 6c: Select Best 2 from Each Priority
Format Output Report Generate a formatted report organized by priority:
# Backlog Tickets for {project-key}
## Search Criteria
- Project: {project-key}
- Assignee: {assignee or "Unassigned"}
- Days Inactive: {days-inactive}+
- Total Tickets Found: {count}
---
## Critical Priority ({count} tickets)
### 1. {ISSUE-KEY}: {Summary}
**Status:** {status} | **Updated:** {days} days ago | **Reporter:** {name}
**Components:** {components} | **Labels:** {labels}
**Watchers:** {count} | **Comments:** {count}
**Context:**
{2-3 sentence summary of the ticket}
**Recent Activity:**
- {Most recent comment summary or "No recent comments"}
- {Status change or "No status changes"}
- {Blocker/Question if identified}
**Recommendation:** {Why this ticket is suitable to work on or what's needed before starting}
---
### 2. {ISSUE-KEY}: {Summary}
...
---
## High Priority ({count} tickets)
...
## Normal Priority ({count} tickets)
...
## Low Priority ({count} tickets)
...
---
## Summary
- Critical: {count} tickets available
- High: {count} tickets available
- Normal: {count} tickets available
- Low: {count} tickets available
**Suggested Next Steps:**
1. Review the tickets above and select one that matches your expertise
2. Check if the ticket has clear acceptance criteria - if not, consider grooming it first using `/jira:grooming {issue-key}`
3. Use `/jira:solve {issue-key} {remote}` to start working on the ticket
Display Report to User
/jira:grooming for tickets lacking clarity/jira:solve to start working on selected ticketSave Report (Optional)
.work/jira-backlog/{project-key}-{timestamp}.mdError Handling:
~/.config/claude-code/mcp.json doesn't exist, display:
Error: JIRA credentials not configured.
This command requires JIRA credentials from the MCP server configuration file.
File not found: ~/.config/claude-code/mcp.json
Please create this file with your JIRA credentials.
See Prerequisites section for the required mcp.json format and setup instructions.
Error: JIRA credentials incomplete in ~/.config/claude-code/mcp.json
Required fields in .mcpServers.atlassian.env:
- JIRA_URL (e.g., https://redhat.atlassian.net)
- JIRA_USERNAME (your Atlassian account email)
- JIRA_API_TOKEN
See Prerequisites section for the required mcp.json format.
Error: JIRA authentication failed (HTTP 401/403)
Please verify your JIRA credentials in ~/.config/claude-code/mcp.json:
1. Check that JIRA_API_TOKEN is correct and not expired
2. Verify JIRA_USERNAME matches your Atlassian account email
3. Ensure JIRA_URL is correct (e.g., https://redhat.atlassian.net)
4. Test authentication: curl -H "Authorization: Basic $(printf '%s:%s' "$JIRA_USERNAME" "$JIRA_API_TOKEN" | base64 | tr -d '\n')" YOUR_JIRA_URL/rest/api/3/myself
To regenerate your token, visit:
https://id.atlassian.com/manage-profile/security/api-tokens
brew install jq on macOS, apt-get install jq on Linux)Performance Considerations:
.work/jira-backlog/{project-key}/batch-*.json - Raw JIRA API responses (one per 1000 tickets).work/jira-backlog/{project-key}/process_batches.py - Python script for filtering.work/jira-backlog/{project-key}/filtered.json - All filtered tickets grouped by priority.work/jira-backlog/{project-key}/stats.json - Priority distribution statistics.work/jira-backlog/{project-key}-{timestamp}.md containing the full reportNote: All examples require JIRA credentials to be configured in ~/.config/claude-code/mcp.json (see Prerequisites section). The command uses curl to fetch data directly from JIRA's REST API, bypassing MCP commands to avoid 413 errors with large datasets.
Find unassigned tickets in OCPBUGS project:
/jira:backlog OCPBUGS
Output: Intelligently analyzes tickets and shows 2 recommended tickets from each priority level (Critical, High, Normal, Low)
Example performance (tested October 31, 2025):
Find stale tickets with custom inactivity threshold:
/jira:backlog OCPBUGS --days-inactive 14
Output: Report showing tickets with no activity for 14+ days, 2 per priority level
Find tickets assigned to a specific user that are stale:
/jira:backlog OCPBUGS --assignee jsmith --days-inactive 30
Output: Report showing tickets assigned to jsmith with 30+ days of inactivity, 2 per priority level
Find tickets in Hypershift project:
/jira:backlog HYPE
Output: Analyzes backlog and shows best 2 tickets from each priority in HYPE project
Find tickets in CNV project:
/jira:backlog CNV
Output: Report showing available backlog tickets across all priorities in CNV project
Performance Note: The curl-based approach can handle large backlogs efficiently. In testing with OCPBUGS (2,535 tickets), the command successfully fetched and processed all tickets without hitting Claude's token limits or encountering 413 errors.
--assignee (optional): Filter by assignee username
--assignee jsmith finds jsmith's stale tickets--days-inactive (optional): Number of days of inactivity to consider a ticket stale
--days-inactive 14 finds tickets with 14+ days of no activitynpx claudepluginhub cali0707/openshift-eng-ai-helpers --plugin jira2plugins reuse this command
First indexed Jul 18, 2026
/backlogConverts ArcKit requirements into a prioritized product backlog with GDS-compliant user stories, organized into sprints with multi-factor scoring.
/backlogFinds suitable JIRA tickets from the backlog by analyzing priority and activity, selecting unassigned or bot-assigned tickets across Critical, High, Normal, and Low priorities.