Skip to content
All AI assets

Triage agent · Jira Service Management

Product Support Triage Agent

A Rovo agent that classifies every new ticket the moment it enters the Product Support queue in Jira Service Management (JSM), using a deterministic three-stage decision framework and returning strict JSON that JSM Automation maps into routing and telemetry fields. Every ticket gets labeled at creation.

My role
Builder and AI architect
When
2025 – present
Tools
Atlassian Rovo, Jira Service Management, JSM Automation, Confluence, Prompt architecture
Who it helps
Product Support Engineers and triagers on the PSRD (Product Support Remediation Desk) board, who get a consistent, rule-based classification on every incoming ticket instead of ad-hoc manual triage.
How it works
Jira Service Management (JSM) is Atlassian's ITSM platform, where Product Support tickets are submitted, queued, and worked. When a new ticket enters the PSRD queue, a JSM Automation rule passes its summary and description to the agent. The agent applies a three-stage framework (workType, then requestType and psCategory from priority-ordered tables, then confidence and clarification) and returns one valid JSON object. Automation writes that output into telemetry fields. A human triager confirms the production Request Type and PS Category, which automation never overwrites in this version.
My contribution
Ran the build like a product manager: discovery into the triage problem and the PSRD taxonomy, a PRD, then a detailed spec (the three-stage framework, tiebreaker rules, and labeled few-shot examples), then testing against real tickets. Owned change management, keeping the Rovo prompt, the automation trigger instructions, and the Confluence documentation in sync, and set up the feedback loop: the triager who sees the ticket logs feedback directly, which drives prompt and logic iteration.
Why it’s valuable
Replaces inconsistent manual first-touch triage with a deterministic, auditable classification that routes tickets the same way every time, flags non-PSRD work for review, and improves through feedback logged by the people who see the tickets.

Approach

  1. Worked within the core constraint of an agent that lives inside a JSM Automation rule rather than a chat window. It gets one shot with the ticket summary and description and no follow-up questions, so every classification rule had to be in the prompt up front.
  2. Designed a deterministic three-stage decision framework so classifications follow explicit rules and labeled examples rather than open-ended judgment. Stage 1 sets workType, Stage 2 maps requestType and psCategory via priority-ordered tables, Stage 3 sets confidence and clarification.
  3. Encoded six Incident subcategories (Stakeholder Escalation, Linked to Problem, Partner/Aggregator Outage, Institution Connectivity Failure, Data Quality Incident, Client Outage), evaluated in strict priority order. First match wins.
  4. Encoded Problem subcategories (Aggregator Cleanup/Migration, Performance Trend/Conversion, RCA, and an Investigate a Problem catch-all) with a fallback mapping table for cases where a specific Request Type ID or PS problem category is unavailable.
  5. Encoded five Service Request subcategories (Connectivity feature/Configuration, Scrape/New Connectivity Method, Data/Reporting support, Alert/Monitoring configuration, General Inquiry) with explicit key-signal triggers.
  6. Wrote seven disambiguation tiebreakers that take priority over general signal matching. For example: an FI-specific failure defaults to Institution Connectivity Failure until multi-FI scope is confirmed, stakeholder escalation always overrides technical cause, and an active issue is never upgraded from Incident to Problem.
  7. Calibrated the agent with fourteen labeled few-shot examples (A through N) covering canonical incidents, problems, service requests, and negative non-PSRD cases.
  8. Enforced strict JSON-only output (no code block, no preamble) because the agent runs headless inside JSM Automation. Any wrapping breaks the `{{agentResponse.asObject.*}}` parse.
  9. Wired the JSM Automation rule: trigger when a ticket enters the PSRD queue (ignoring `spectre_alert` and Request Type ID 889), call the agent, then branch on `nonPsrd` to either route to Needs Review or write the PSRD-work fields.
  10. Designed the telemetry so agent outputs land in `(Rovo)` reference fields for human validation, with an `agentFeedback (Rovo)` field the triager fills in by hand to drive prompt and logic iteration.

Outcomes

  • Classifies 100% of Product Support tickets on creation with a workType, requestType, and psCategory. That is coverage, not measured accuracy. Triagers get a consistent starting point on every ticket.
  • Non-PSRD tickets are flagged Needs Review with a rationale comment, keeping the board clear of out-of-scope work.
  • Non-destructive v1: automation writes suggestions to telemetry and reference fields only, so production Request Type and PS Category are never overwritten without human confirmation.
  • A feedback loop (manual feedback from the triager who sees the ticket) drives ongoing prompt and logic updates.
  • The full system (field mappings, automation logic, troubleshooting, and a ready-to-paste prompt insert) is documented in Confluence for ops handoff and change control.

What I learned

  • An agent embedded in an automation is a different problem from a chat agent. It runs headless, one-shot, with no follow-ups, which makes deterministic rules and exhaustive few-shot coverage non-negotiable.
  • Rule-ordered classification with labeled examples beats open-ended LLM judgment for routing decisions that must be auditable and consistent.
  • Strict JSON-only output is what makes an LLM agent safely callable from JSM Automation. Any prose wrapping breaks the parse.
  • Making v1 non-destructive (suggestions to telemetry fields, humans confirm production fields) built trust with triagers and kept the rollout low-risk.
  • Tiebreakers with an explicit priority order are essential for edge cases. Without them, plausible but conflicting signals produce inconsistent routing.

Overview

Jira Service Management (JSM) is Atlassian’s IT service management platform, the system where Product Support tickets are submitted, queued, and worked. The PSRD (Product Support Remediation Desk) board is the JSM project that receives them. Every ticket that enters the PSRD queue needs a consistent first-touch classification: is this an Incident, a Problem, or a Service Request? Which request type and PS category does it map to? Does it belong on this board at all? Manual triage produced inconsistent answers, especially on edge cases like aggregator-wide outages versus single-FI failures, or active incidents that also reference a historical pattern.

The Product Support Triage Agent is a Rovo agent that classifies every new ticket the moment it enters the PSRD queue and returns a strict JSON payload that JSM Automation maps into routing and telemetry fields. It does not replace the human triager. It produces suggestions that a PSE confirms, and it removes the cold-start ambiguity from every incoming ticket.

Why this build was different: an agent inside an automation

Most Rovo agents are conversational. A person chats with them, refines a request, and iterates. This agent lives inside a JSM Automation rule, not a chat window, and that shaped every design decision:

  • One shot, no follow-ups. The agent receives only the ticket’s summary and description and gets a single turn to classify it. It cannot ask the reporter a clarifying question, so clarificationNeeded and clarificationQuestion exist as outputs for the human triager, not as a back-and-forth with the reporter.
  • Headless execution. No human reads the raw response. JSM Automation parses {{agentResponse.asObject.*}} directly into custom fields, which is why the output is strict JSON only: no code blocks, no preamble, no prose. Any wrapping breaks the parse and the rule fails silently.
  • All logic lives in the prompt. The agent cannot be reconfigured at runtime, so every classification rule, tiebreaker, fallback mapping, and few-shot example had to be encoded up front. The three-stage framework, the priority-ordered subcategory tables, and the seven tiebreakers exist because the agent has to handle every case in a single pass.
  • Trigger and filter design. The automation fires only on the right tickets: it triggers on PSRD queue entry, ignores spectre_alert tickets and Request Type ID 889, then branches on nonPsrd to route non-PSRD work to Needs Review.
  • Non-destructive by necessity. The agent runs on every ticket with no human gate before it acts, so v1 writes only to telemetry and reference fields. Production Request Type and PS Category are never overwritten without a triager’s confirmation. An automation-driven agent that silently mutates production fields is a trust and auditability risk.

Building an agent that lives inside an automation is a different engineering problem from building a chat agent. It has to be deterministic, self-contained, parse-safe, and safe to run on every ticket without supervision.

The three-stage decision framework

The agent follows an explicit, ordered framework rather than open-ended judgment:

Stage 1: workType

Classify the ticket as Incident, Problem, or Service Request.

Stage 2: requestType and psCategory

Once workType is set, evaluate a priority-ordered subcategory table and take the first match.

  • Stage 2a (Incident): six subcategories evaluated in priority order: Stakeholder Escalation, Linked to Problem, Partner/Aggregator Outage, Institution Connectivity Failure, Data Quality Incident, Client Outage/Degradation.
  • Stage 2b (Problem): Aggregator Cleanup/Migration, Performance Trend/Conversion, RCA, or the catch-all Investigate a Problem, with a fallback mapping table for cases where a specific Request Type ID or PS problem category is unavailable.
  • Stage 2c (Service Request): Connectivity feature/Configuration, Scrape/New Connectivity Method, Data/Reporting support, Alert/Monitoring configuration, or General Inquiry.

Stage 3: confidence and clarification

Assign High / Medium / Low confidence and a clarification flag based on decision-tree match quality, lexical signal strength, whether tiebreakers were needed, and similarity to the labeled examples. Low confidence always sets clarificationNeeded: "True" and one targeted question about the single unknown that would most change routing.

Tiebreakers: the edge-case rules

Edge cases are where deterministic triage matters most. Seven tiebreaker rules take priority over general signal matching, applied in order:

  1. FI-specific vs. aggregator-wide. Default to Institution Connectivity Failure. Upgrade to Partner/Aggregator Outage only when multi-FI impact is explicitly confirmed.
  2. Stakeholder escalation overrides technical cause. CSM, AM, or executive origin, or escalation language, always classifies as Stakeholder Escalation.
  3. An active issue is an Incident. A ticket opened as an active problem right now is an Incident even if a pattern is mentioned. Create a separate Problem for the pattern.
  4. Broken config with active impact is an Incident. If clients are impacted now, it is an Incident. If the config is wrong but not yet causing impact, it is a Service Request.
  5. Specific Problem subtype over catch-all. Use Investigate a Problem only when the subtype is unclear at intake.
  6. Single-client data defect vs. systemic. One client or FI affected now is an Incident. Multiple clients or FIs from the same underlying defect is a Problem.
  7. Non-PSRD detection. Internal Eng/TOPS tasks and documentation requests are not PSRD work. Flag nonPsrd and route to Needs Review.

The output schema

The agent returns one JSON object (no code block, no preamble, no "fields" wrapper) that JSM Automation parses directly:

{
  "workType": "Incident" | "Problem" | "Service Request",
  "requestType": "<value from Stage 2 tables>",
  "psCategory": "<value from approved list>",
  "confidence": "High" | "Medium" | "Low",
  "clarificationNeeded": "True" | "False",
  "clarificationQuestion": "<single concise question, or omit if false>",
  "rationale": "<1-2 sentence plain-English reasoning>",
  "nonPsrd": "True" | "False",
  "routeTo": "PSRD board" | "Internal/TOPS" | "TechOps Docs" | "Needs Review"
}

How automation consumes it

A JSM Automation rule triggers the moment a ticket enters the PSRD queue (ignoring spectre_alert tickets and Request Type ID 889), passes {{issue.summary}} and {{issue.description}} to the agent, and branches on the response:

  • If nonPsrd = "True": sets Needs Review, writes confidence, clarification, and rationale, and adds an explanatory comment.
  • Otherwise (PSRD work): writes workType, confidence, clarificationNeeded, rationale, nonPsrd, and routeTo into the corresponding (Rovo) telemetry custom fields.

This version is non-destructive: requestType and psCategory suggestions land in telemetry and reference fields, and the production Request Type and PS Category are never overwritten by automation. A human triager reviews and confirms those.

The feedback loop

Every agent output is captured in (Rovo) custom fields for human validation. A separate agentFeedback (Rovo) field lets the triager who sees the ticket note when the agent got it wrong. That feedback goes straight into prompt and logic updates, so accuracy improves with each iteration.

Email copied: mitchellgdyer@gmail.com