Automated summary
Triages PRODINT intake tickets by querying queues, parsing descriptions, and transitioning statuses.
Strengths
- Works around JSM API limitations by using REST API directly
- Parses ADF description to extract impact and affected parties
- Automatically detects potential incidents
- Interactive triage flow with customizable comments
Limitations
- Requires preconfigured Jira CLI and API token
- Only works with the PRODINT project
- Depends on specific transition and status names
When you need to triage assigned JSM intake tickets without manually using the Jira UI.
For projects outside PRODINT or when Jira credentials are unavailable.
Security analysis
SafeThe skill reads configuration, queries Jira via REST API, and transitions tickets using CLI commands. No destructive actions, data exfiltration, or obfuscation. All tools are used for legitimate triage tasks.
No concerns found
How this analysis is madeExamples
Check my PRODINT intake queue for new tickets.Triage ticket PRODINT-123 and move it to Accepted.Check if ticket PRODINT-456 is a potential incident based on impact and affected parties.name: product-triage description: Triage PRODINT intake tickets interactively. Query queue, assess severity, transition statuses, draft template comments, and clone accepted tickets to PYR backlog. Use when Ivy says /product-triage, "check my intake queue", "triage tickets", or "check PRODINT". allowed-tools: Bash, Read, Grep, AskUserQuestion
Payer Product Intake Triage
Triage PRODINT intake tickets assigned to you. Review queue, transition statuses, draft comments interactively, and clone accepted tickets to PYR.
Configuration
Read configuration from ~/.claude/skills/triage/defaults/config.md at the start of every invocation to get project keys, team name, field mappings, transition names, and comment templates.
Key settings:
- Intake project: PRODINT
- Delivery project: PYR
- Delivery team: Orchestration (option ID: 23029)
- Default issue type: Bug
- Default priority: Medium
Step 1: Check Prerequisites
Before querying, verify the environment:
which jira && echo "jira CLI: OK" || echo "ERROR: jira CLI not installed. Run: brew install ankitpokhrel/jira-cli/jira-cli"
[ -n "$JIRA_API_TOKEN" ] && echo "API token: OK" || echo "ERROR: JIRA_API_TOKEN not set. Add to ~/.zshrc"
If either check fails, tell the user what to fix and stop.
Step 2: Query the Intake Queue
IMPORTANT: Always use REST API v3 for PRODINT queries. The jira CLI cannot query JSM projects (permission issue). Do NOT try the CLI first.
Default query (New tickets):
JIRA_SERVER=$(grep "^server:" ~/.config/.jira/.config.yml | awk '{print $2}')
JIRA_EMAIL=$(grep "^login:" ~/.config/.jira/.config.yml | awk '{print $2}')
curl -s -H "Content-Type: application/json" \
-u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \
"${JIRA_SERVER}/rest/api/3/search/jql?jql=project%3DPRODINT%20AND%20assignee%3DcurrentUser()%20AND%20status%3D%27New%27%20ORDER%20BY%20created%20ASC&fields=summary,reporter,priority,created,status,description,attachment" | python3 -m json.tool
Other queue queries (user can request with queue review, queue needs more info, queue all):
queue review: Change status filter tostatus%3D%27In%20Review%27queue needs more info: Change status filter tostatus%3D%27Needs%20More%20Info%27queue all: Change status filter tostatus%20in%20(%27New%27%2C%27In%20Review%27%2C%27Needs%20More%20Info%27)queue accepted: Change status filter tostatus%3D%27Accepted%27
IMPORTANT: Transition names ≠ Status names in JSM.
- Use transition names with
jira issue move: "Needs Review", "Needs Info", "Accepted", "Declined" - Use status names in JQL queries: "In Review", "Needs More Info", "Accepted", "Declined"
Always include description in the fields list to parse Impact and Who Affected.
Step 2a: Parse Impact & Who Affected from ADF Description
Impact and urgency are NOT separate Jira fields. They are embedded in the description ADF from the intake form. Parse them by finding bold text labels and extracting the following text node.
Key labels to extract:
- "How is this impacting work?" → Impact value (e.g., "Blocking work (no workaround available)")
- "Who is most affected by this issue?" → Who Affected value (e.g., "Multiple teams")
- "System / Product Area:" → Product Area (e.g., "Retrieval Hub")
ADF parsing approach: Walk the ADF content tree. For each paragraph, find bold text nodes matching these labels, then capture the next non-bold text node as the value (it follows a hardBreak node).
Step 2b: Incident Flag
After parsing Impact and Who Affected, check for potential incidents:
If Impact = "Blocking work (no workaround available)" AND Who Affected = "Multiple teams", display a warning:
*** POTENTIAL INCIDENT ***
This ticket reports blocking impact across multiple teams.
Consider whether this should be handled through the formal incident process
rather than intake triage. Incidents are managed separately -- not through PRODINT.
This is a flag only — the user decides whether to escalate or continue normal triage.
Step 3: Display the Queue
Present results in this format:
PRODINT Intake Queue -- {count} ticket(s) in {status}
1. {KEY} | {Summary}
Reporter: {reporter} | Priority: {priority}
Impact: {impact} | Who Affected: {who_affected}
Attachments: {count} file(s) -- view at {jira_url} (only if attachments exist)
Created: {date} ({business_days} business day(s) ago) {aging_flag}
{incident_flag_if_applicable}
2. ...
Attachments in queue view: Include attachment in the query fields list. If a ticket has attachments, show count and a link to the ticket in Jira (e.g., "Attachments: 2 file(s) -- view at https://datavant.atlassian.net/browse/PRODINT-384"). If no attachments, omit the line entirely to keep the queue compact.
Aging Logic (Business Days Only)
Calculate business days since created date (exclude Saturdays and Sundays):
- 0 business days (created today) -> no flag
- 1 business day -> no flag
- 2+ business days -> append "-- approaching escalation window"
If the queue is empty, say:
PRODINT Intake Queue -- No tickets in {status}. You're all caught up.
Then ask: "Would you like to check tickets in other statuses? (queue review / queue needs more info / queue all)"
Step 4: Handle Triage Actions
After displaying the queue, wait for the user's instruction. They will say things like:
Queue commands:
- "queue review" or "queue needs more info" or "queue all" (query other statuses)
Single ticket actions:
- "review 42" or "review PRODINT-42"
- "review 42 -- we are looking into this" (review with acknowledgment comment)
- "need more info on 43" or "needs more info 43"
- "needs more info 43 -- need env and screenshot" (inline with context)
- "accept 42"
- "accept 42 as Story/High" (inline accept with overrides)
- "decline 44"
- "decline 44 -- not repro, tested in prod" (inline decline)
- "show 42" (view full details)
Batch ticket actions (multiple tickets at once):
- "review 385 386" or "review 385 386 -- we are investigating"
- "accept 385 386" (uses defaults for all)
- "accept 385 386 as Story/High" (same overrides applied to all)
- "decline 385 386 -- not repro, tested in prod" (same reason for all)
Always normalize ticket references: If user says just a number (e.g., "42"), prepend "PRODINT-" to make "PRODINT-42". For batch, normalize all numbers.
Action: Show (View Details)
Use REST API directly (jira CLI has inconsistent behavior with JSM):
JIRA_SERVER=$(grep "^server:" ~/.config/.jira/.config.yml | awk '{print $2}')
JIRA_EMAIL=$(grep "^login:" ~/.config/.jira/.config.yml | awk '{print $2}')
curl -s -u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \
"${JIRA_SERVER}/rest/api/3/issue/PRODINT-{number}?fields=summary,description,reporter,created,priority,status,comment,attachment" | python3 -m json.tool
Display: summary, reporter, created date, priority, Impact, Who Affected, Product Area, description details (parsed from ADF format), attachments, and any comments.
Attachments: Include attachment in the fields list. For each attachment, display:
- Filename
- Size (human-readable, e.g., "345 KB")
- Link to view:
https://{JIRA_SERVER}/browse/PRODINT-{number}(direct attachment content URLs require auth, so link to the ticket instead)
If no attachments, show "(none)".
Also check for the incident flag (Blocking + Multiple teams) and display the warning if triggered.
Action: Review (New -> Needs Review)
Supports batch and inline comments.
Basic: review 42 — no comment, just transition.
With comment: review 42 -- we are looking into this — transition + add comment.
Batch: review 385 386 — transition all tickets. Run transitions in parallel (separate Bash calls).
Batch with comment: review 385 386 -- investigating — transition + same comment on all.
For each ticket:
jira issue move PRODINT-{number} "Needs Review"
If an inline comment was provided:
jira issue comment add PRODINT-{number} "{comment}" --no-input
IMPORTANT: Never chain jira CLI commands with && or ;. The jira CLI hangs when chained. Always run comment and transition as separate Bash calls.
For batch operations, run all transitions in parallel (separate Bash tool calls), then all comments in parallel.
Confirm to user: "Moved PRODINT-{number} to Needs Review." (or summary table for batch)
Action: Need More Info (Needs Review -> Needs Info)
This is a streamlined flow. Minimize back-and-forth.
Inline mode: If the user provides context in their command (e.g., "needs more info 43 -- need env and screenshot"), use that directly. Do NOT ask again what info is needed.
Interactive mode: If the user just says "needs more info 43" with no context, ask ONE question:
Using AskUserQuestion:
- Question: "What information do you need from the reporter?"
- This is open-ended -- let the user type freely
Then, in both modes:
- Draft the comment using the template:
We need additional detail to proceed:
- {question 1}
- {question 2}
...
Once received, we will continue investigation.
Format each point as a clean bullet. Clean up grammar if needed but preserve meaning.
-
Show the drafted comment and ask: "Post this and move to Needs Info? (y/n)"
-
If confirmed, execute as separate Bash calls (never chain with &&):
# Call 1: Add comment (positional arg, NOT -m flag)
jira issue comment add PRODINT-{number} $'formatted\ncomment\nhere' --no-input
# Call 2: Transition (separate Bash call)
jira issue move PRODINT-{number} "Needs Info"
- Confirm: "Posted comment and moved PRODINT-{number} to Needs Info."
Action: Accept (Needs Review -> Accepted)
This is a single-confirmation flow. Use smart defaults, don't over-ask. Supports batch.
Defaults: Bug / Medium / Orchestration / no extra context.
Step 1: Check for inline overrides. If the user says:
- "accept 42" -> use all defaults
- "accept 42 as Story" -> override issue type only
- "accept 42 as Story/High" -> override issue type and priority
- "accept 42 -- context: affects Centene wave 4" -> add context to description
- "accept 385 386" -> batch accept with defaults (same overrides apply to all)
Step 2: Only ask if info is missing AND not using defaults. If the user said "accept 42" with no overrides, do NOT ask for issue type, priority, or context. Just use defaults.
If overrides are partially given and something is ambiguous, ask a single focused AskUserQuestion.
Batch mode: For multiple tickets (e.g., "accept 385 386"):
- Fetch all ticket details in parallel (separate Bash calls)
- Show a single confirmation listing all tickets
- Execute sequentially per ticket (create PYR → link → comment → transition) but parallelize independent steps across tickets where possible
- Show a summary table at the end
Step 3: Get PRODINT ticket details via REST API (for batch, fetch all in parallel):
JIRA_SERVER=$(grep "^server:" ~/.config/.jira/.config.yml | awk '{print $2}')
JIRA_EMAIL=$(grep "^login:" ~/.config/.jira/.config.yml | awk '{print $2}')
curl -s -u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \
"${JIRA_SERVER}/rest/api/3/issue/PRODINT-{number}?fields=summary,description" | python3 -m json.tool
Step 4: Show plan and confirm (ONE confirmation):
Accepting PRODINT-{number}:
PYR ticket: Bug | Medium | Orchestration
Summary: "{summary}"
{if additional context: "Extra context: ..."}
This will create the PYR ticket, link it, comment on PRODINT, and transition to Accepted.
Proceed? (y/n)
Step 5: If confirmed, execute in order:
- Create the PYR ticket:
~/.claude/skills/triage/scripts/create-pyr-ticket.sh \
"{summary}" \
"{description_plus_additional_context}" \
"{issue_type}" \
"{priority}"
Capture the returned PYR key from stdout.
- Link the tickets:
~/.claude/skills/triage/scripts/link-jira-tickets.sh \
"{PYR_KEY}" \
"PRODINT-{number}" \
"Cloners"
- Add the comment to PRODINT (positional arg, NOT -m flag):
jira issue comment add PRODINT-{number} "We have confirmed this issue and are moving it into the team backlog for resolution. You can track progress via the linked ticket: {PYR_KEY}." --no-input
- Transition PRODINT:
jira issue move PRODINT-{number} "Accepted"
- Verify the link is visible on the intake ticket:
JIRA_SERVER=$(grep "^server:" ~/.config/.jira/.config.yml | awk '{print $2}')
JIRA_EMAIL=$(grep "^login:" ~/.config/.jira/.config.yml | awk '{print $2}')
curl -s -u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \
"${JIRA_SERVER}/rest/api/3/issue/PRODINT-{number}?fields=issuelinks" | python3 -c "
import sys, json
data = json.loads(sys.stdin.read())
links = data.get('fields', {}).get('issuelinks', [])
found = any(
l.get('inwardIssue', {}).get('key', '').startswith('PYR') or
l.get('outwardIssue', {}).get('key', '').startswith('PYR')
for l in links
)
print('LINK_VERIFIED' if found else 'LINK_NOT_FOUND')
"
If LINK_NOT_FOUND, warn: "Link may not have been created. Please verify manually in Jira."
If any step (1-4) fails, stop and tell the user which step failed and what to do. Do NOT continue to the next step if a previous step failed. Step 5 (verification) is non-blocking — just warn if it fails.
Step 6: Confirm: "Done. Created {PYR_KEY}, linked to PRODINT-{number}, and moved to Accepted. Link verified."
Action: Decline (Needs Review -> Declined)
Minimize prompts. One question max, or zero if inline.
Inline mode: If the user provides reason in their command, use it directly. Examples:
- "decline 42 -- not reproducible, tested in prod and staging" -> draft comment immediately
- "decline 42 -- working as designed, this is expected behavior for NEM routing" -> draft immediately
Parse the inline text to determine the category (not reproducible / working as designed / already resolved) and use the rest as the explanation.
Interactive mode: If the user just says "decline 42" with no context, ask ONE question using AskUserQuestion:
- Question: "Why are you declining? Pick a reason and add a brief explanation (e.g., 'Not reproducible -- tested in prod and staging, no errors found')."
- Options: "Not reproducible", "Working as designed", "Already resolved"
- The user can type freely with a custom response that includes both reason and explanation
If the user only picks a category with no explanation, use a generic explanation (e.g., "we were unable to identify the reported issue" for not reproducible). Do NOT ask a follow-up.
Then, in both modes:
- Draft the comment using the appropriate template. Adapt opening based on decline reason:
-
Not reproducible:
We reviewed this issue and were not able to reproduce the reported behavior. Based on investigation, {explanation}. We are marking this as Declined. Please reopen if new information becomes available. -
Working as designed:
We reviewed this issue and determined it is working as designed. {explanation}. We are marking this as Declined. Please reopen if new information becomes available. -
Already resolved:
We reviewed this issue and confirmed it has been resolved. {explanation}. We are marking this as Declined. Please reopen if new information becomes available.
-
Show the drafted comment and ask: "Post this and move to Declined? (y/n)"
-
If confirmed, execute as separate Bash calls (never chain with &&):
# Call 1: Add comment (positional arg, NOT -m flag)
jira issue comment add PRODINT-{number} 'formatted comment here' --no-input
# Call 2: Transition (separate Bash call)
jira issue move PRODINT-{number} "Declined"
- Confirm: "Posted comment and moved PRODINT-{number} to Declined."
After Each Action
After each triage action, ask: "Anything else to triage, or are we done?"
If done and there are still tickets in New, remind the user: "Note: {X} ticket(s) still in New. Remember the 1-business-day SLA."
Slack Redirect
If the user mentions someone raised an issue in Slack instead of through intake, offer this response they can copy-paste:
Thanks for flagging this. Please log this via the Payer Product Support form so we can properly track and triage it. Once submitted, we'll review there.
Error Handling
- jira CLI not installed: Tell user to run
brew install ankitpokhrel/jira-cli/jira-cli - JIRA_API_TOKEN not set: Tell user to set it in ~/.zshrc
- PRODINT query fails: Use REST API v3 (never use jira CLI for PRODINT queries). If REST also fails, tell user to verify JSM Agent license and PRODINT project access.
- Transition fails: Use the exact transition names from config.md. If a name still fails, discover available transitions via REST API:
Then use the transition ID directly via REST API POST.JIRA_SERVER=$(grep "^server:" ~/.config/.jira/.config.yml | awk '{print $2}') JIRA_EMAIL=$(grep "^login:" ~/.config/.jira/.config.yml | awk '{print $2}') curl -s -u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \ "${JIRA_SERVER}/rest/api/2/issue/PRODINT-{number}/transitions" | python3 -c " import sys, json data = json.loads(sys.stdin.read()) for t in data.get('transitions', []): print(f' ID: {t[\"id\"]:5s} Name: {t[\"name\"]}')" - PYR ticket creation fails: Show the error, suggest creating manually, and provide all the details to copy.
- Link type wrong: The link script will automatically show available link types on failure. Try "Cloners" first, then "Relates".
- Comment fails: Show error, provide the comment text so user can paste it manually in Jira.
Command Reference (Quick)
| Command | What it does |
|---------|-------------|
| Queue | |
| queue review | Show tickets in In Review |
| queue needs more info | Show tickets in Needs More Info |
| queue all | Show tickets in New + In Review + Needs More Info |
| Single ticket | |
| show 42 | View full details (Impact, Who Affected, attachments) |
| review 42 | New -> Needs Review (no comment) |
| review 42 -- looking into this | New -> Needs Review + acknowledgment comment |
| needs more info 42 | In Review -> Needs More Info (asks for questions) |
| needs more info 42 -- need env and screenshot | In Review -> Needs More Info (uses inline context) |
| accept 42 | Needs Review -> Accepted (Bug/Medium defaults) |
| accept 42 as Story/High | Needs Review -> Accepted (with overrides) |
| decline 42 | Needs Review -> Declined (asks for reason) |
| decline 42 -- not repro, tested in prod | Needs Review -> Declined (uses inline reason) |
| Batch | |
| review 385 386 | Move multiple tickets to Needs Review |
| review 385 386 -- investigating | Move multiple + same comment on all |
| accept 385 386 | Accept multiple with defaults |
| accept 385 386 as Story/High | Accept multiple with same overrides |
| decline 385 386 -- not repro | Decline multiple with same reason |
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/product-intake-triage-mrx3xx83/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/product-intake-triage-mrx3xx83' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/product-intake-triage-mrx3xx83/download' --output '.skill-downloads/product-intake-triage-mrx3xx83/SKILL.md.part' && mv '.skill-downloads/product-intake-triage-mrx3xx83/SKILL.md.part' '.skill-downloads/product-intake-triage-mrx3xx83/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
Tools declared by the author (check availability in your agent): Bash, Read, Grep, AskUserQuestion
No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.
Claude Code
test -f '.skill-downloads/product-intake-triage-mrx3xx83/SKILL.md' && test -s '.skill-downloads/product-intake-triage-mrx3xx83/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/product-triage' && cp -R '.skill-downloads/product-intake-triage-mrx3xx83' '.claude/skills/product-triage'Cursor
test -f '.skill-downloads/product-intake-triage-mrx3xx83/SKILL.md' && test -s '.skill-downloads/product-intake-triage-mrx3xx83/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/product-triage' && cp -R '.skill-downloads/product-intake-triage-mrx3xx83' '.cursor/skills/product-triage'OpenSkills
OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.
Official OpenSkills installationopenskills install './.skill-downloads/product-intake-triage-mrx3xx83'openskills read 'product-intake-triage-mrx3xx83'Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.
For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.
openskills syncManual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/product-intake-triage-mrx3xx83/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
React Hook Form Best Practices
Development
Master React Hook Form: avoid anti-patterns, manage subscriptions, and handle reset, dirty state, and controlled inputs correctly.
Emotion to Mantine Migration
Development
Migrate Emotion styled-components to Mantine components with style props and CSS modules. Use when converting .styled.tsx files or removing @emotion imports.
Scope Creep Detector
Development
Analyzes git diffs against a stated intent to detect scope creep, unrelated files, broad PRs, and oversized changes, then suggests keep, split, or justify actions.