packages/opencode/src/bundled-skills/incident-management/SKILL.md
This skill should be used when the user asks to "create incident", "incident workflow", "incident assignment", "major incident", "incident escalation", "incident priority", or any ServiceNow Incident Management development.
npx skillsauth add groeimetai/snow-flow incident-managementInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Incident Management restores normal service operation as quickly as possible while minimizing business impact.
New (1)
↓
In Progress (2)
↓ ← On Hold (3)
Resolved (6)
↓
Closed (7)
Cancelled (8) ← Can occur from New/In Progress
| Table | Purpose |
| ---------------- | ----------------------- |
| incident | Incident records |
| incident_task | Sub-tasks for incidents |
| incident_alert | Related alerts |
| problem | Related problems |
// Create incident (ES5 ONLY!)
var incident = new GlideRecord("incident")
incident.initialize()
// Required fields
incident.setValue("caller_id", callerSysId)
incident.setValue("short_description", "Email not working")
incident.setValue("description", "User cannot send or receive emails since this morning")
// Classification
incident.setValue("category", "software")
incident.setValue("subcategory", "email")
incident.setValue("impact", 2)
incident.setValue("urgency", 2)
// Priority is calculated automatically from impact/urgency
// Assignment
incident.setValue("assignment_group", getGroupSysId("Email Support"))
// Optional: affected CI
incident.setValue("cmdb_ci", emailServerSysId)
var incidentSysId = incident.insert()
gs.info("Created incident: " + incident.getValue("number"))
// Priority calculation (ES5 ONLY!)
// Priority = Impact x Urgency matrix
var priorityMatrix = {
"1-1": 1, // High Impact + High Urgency = Critical
"1-2": 2, // High Impact + Medium Urgency = High
"1-3": 3, // High Impact + Low Urgency = Moderate
"2-1": 2, // Medium Impact + High Urgency = High
"2-2": 3, // Medium Impact + Medium Urgency = Moderate
"2-3": 4, // Medium Impact + Low Urgency = Low
"3-1": 3, // Low Impact + High Urgency = Moderate
"3-2": 4, // Low Impact + Medium Urgency = Low
"3-3": 5, // Low Impact + Low Urgency = Planning
}
function calculatePriority(impact, urgency) {
var key = impact + "-" + urgency
return priorityMatrix[key] || 4
}
// Assignment rule script (ES5 ONLY!)
// Business Rule: before, insert, incident
;(function executeRule(current, previous) {
// Skip if already assigned
if (current.assignment_group) {
return
}
var group = determineAssignmentGroup(current)
if (group) {
current.assignment_group = group
// Optionally assign to on-call
var onCallUser = getOnCallUser(group)
if (onCallUser) {
current.assigned_to = onCallUser
}
}
})(current, previous)
function determineAssignmentGroup(incident) {
var category = incident.getValue("category")
var subcategory = incident.getValue("subcategory")
// Category-based assignment
var mapping = {
network: "Network Support",
hardware: "Desktop Support",
"software-email": "Email Support",
"software-erp": "ERP Support",
database: "Database Admins",
}
var key = category
if (subcategory) {
key = category + "-" + subcategory
}
var groupName = mapping[key] || mapping[category] || "Service Desk"
var group = new GlideRecord("sys_user_group")
if (group.get("name", groupName)) {
return group.getUniqueValue()
}
return null
}
// Track reassignments (ES5 ONLY!)
// Business Rule: before, update, incident
;(function executeRule(current, previous) {
// Check if assignment group changed
if (current.assignment_group.changes()) {
// Increment reassignment count
var count = parseInt(current.getValue("reassignment_count"), 10) || 0
current.reassignment_count = count + 1
// Add work note
current.work_notes =
"Reassigned from " +
previous.assignment_group.getDisplayValue() +
" to " +
current.assignment_group.getDisplayValue()
// Alert if excessive reassignments
if (count >= 3) {
gs.eventQueue("incident.excessive.reassignments", current, count.toString(), "")
}
}
})(current, previous)
// Declare major incident (ES5 ONLY!)
function declareMajorIncident(incidentSysId, reason) {
var incident = new GlideRecord("incident")
if (!incident.get(incidentSysId)) {
return false
}
// Set major incident flag
incident.setValue("major_incident_state", "confirmed")
incident.setValue("priority", 1)
// Set major incident fields
incident.setValue("u_major_incident_start", new GlideDateTime())
incident.setValue("u_major_incident_reason", reason)
// Assign to Major Incident team
var miTeam = new GlideRecord("sys_user_group")
if (miTeam.get("name", "Major Incident Team")) {
incident.setValue("assignment_group", miTeam.getUniqueValue())
}
// Add work note
incident.work_notes = "MAJOR INCIDENT DECLARED\nReason: " + reason
incident.update()
// Trigger notifications
gs.eventQueue("incident.major.declared", incident, "", "")
// Create bridge call record
createBridgeCall(incident)
return true
}
function createBridgeCall(incident) {
var bridge = new GlideRecord("u_bridge_call")
bridge.initialize()
bridge.setValue("u_incident", incident.getUniqueValue())
bridge.setValue("u_dial_in", "1-800-555-0123")
bridge.setValue("u_pin", generatePin())
bridge.setValue("u_start_time", new GlideDateTime())
bridge.insert()
}
// Send major incident update (ES5 ONLY!)
function sendMajorIncidentUpdate(incidentSysId, updateText, recipientGroups) {
var incident = new GlideRecord("incident")
if (!incident.get(incidentSysId)) {
return
}
// Add to work notes
incident.work_notes = "MAJOR INCIDENT UPDATE:\n" + updateText
incident.update()
// Build recipient list
var recipients = []
for (var i = 0; i < recipientGroups.length; i++) {
var members = getGroupMembers(recipientGroups[i])
recipients = recipients.concat(members)
}
// Send notification
var eventParams = JSON.stringify({
update: updateText,
recipients: recipients,
})
gs.eventQueue("incident.major.update", incident, eventParams, "")
}
// Escalation script for scheduled job (ES5 ONLY!)
;(function executeScheduledJob() {
var LOG_PREFIX = "[IncidentEscalation] "
// Find incidents needing escalation
var now = new GlideDateTime()
// P1 not acknowledged in 15 minutes
escalateUnacknowledged("1", 15)
// P2 not acknowledged in 30 minutes
escalateUnacknowledged("2", 30)
// P1 not resolved in 4 hours
escalateUnresolved("1", 240)
// P2 not resolved in 8 hours
escalateUnresolved("2", 480)
function escalateUnacknowledged(priority, minutes) {
var threshold = new GlideDateTime()
threshold.addSeconds(-minutes * 60)
var gr = new GlideRecord("incident")
gr.addQuery("priority", priority)
gr.addQuery("state", 1) // New
gr.addQuery("sys_created_on", "<", threshold)
gr.addNullQuery("assigned_to")
gr.query()
while (gr.next()) {
gs.info(LOG_PREFIX + "Escalating unacknowledged P" + priority + ": " + gr.number)
gr.escalation = 1
gr.work_notes = "Auto-escalated: Not acknowledged within " + minutes + " minutes"
gr.update()
gs.eventQueue("incident.escalation.unacknowledged", gr, priority, "")
}
}
function escalateUnresolved(priority, minutes) {
var threshold = new GlideDateTime()
threshold.addSeconds(-minutes * 60)
var gr = new GlideRecord("incident")
gr.addQuery("priority", priority)
gr.addQuery("state", "IN", "1,2") // New or In Progress
gr.addQuery("sys_created_on", "<", threshold)
gr.query()
while (gr.next()) {
var currentEsc = parseInt(gr.getValue("escalation"), 10) || 0
if (currentEsc < 3) {
gr.escalation = currentEsc + 1
gr.work_notes = "Auto-escalated: Not resolved within target time"
gr.update()
notifyNextLevel(gr)
}
}
}
function notifyNextLevel(incident) {
var group = incident.assignment_group.getRefRecord()
if (group.manager) {
gs.eventQueue("incident.escalation.manager", incident, group.manager, "")
}
}
})()
// Resolve incident with validation (ES5 ONLY!)
function resolveIncident(incidentSysId, resolution) {
var incident = new GlideRecord("incident")
if (!incident.get(incidentSysId)) {
return { success: false, message: "Incident not found" }
}
// Validate state transition
var currentState = incident.getValue("state")
if (currentState === "6" || currentState === "7") {
return { success: false, message: "Incident already resolved/closed" }
}
// Validate resolution fields
if (!resolution.code) {
return { success: false, message: "Resolution code is required" }
}
if (!resolution.notes) {
return { success: false, message: "Resolution notes are required" }
}
// Update incident
incident.setValue("state", 6) // Resolved
incident.setValue("resolution_code", resolution.code)
incident.setValue("close_notes", resolution.notes)
incident.setValue("resolved_at", new GlideDateTime())
incident.setValue("resolved_by", gs.getUserID())
// Link to problem/known error if provided
if (resolution.problem) {
incident.setValue("problem_id", resolution.problem)
}
if (resolution.knowledge) {
incident.setValue("u_resolution_article", resolution.knowledge)
}
incident.update()
// Notify caller
gs.eventQueue("incident.resolved", incident, "", "")
return {
success: true,
message: "Incident resolved",
number: incident.getValue("number"),
}
}
// Calculate Mean Time to Resolve (ES5 ONLY!)
function calculateMTTR(startDate, endDate, filters) {
var ga = new GlideAggregate("incident")
ga.addQuery("resolved_at", ">=", startDate)
ga.addQuery("resolved_at", "<=", endDate)
ga.addQuery("state", "IN", "6,7")
// Apply optional filters
if (filters.priority) {
ga.addQuery("priority", filters.priority)
}
if (filters.category) {
ga.addQuery("category", filters.category)
}
ga.addAggregate("AVG", "calendar_duration")
ga.addAggregate("COUNT")
ga.query()
if (ga.next()) {
var avgDuration = ga.getAggregate("AVG", "calendar_duration")
var count = ga.getAggregate("COUNT")
// Convert to hours
var durationObj = new GlideDuration(avgDuration)
var hours = durationObj.getNumericValue() / 3600000
return {
mttr_hours: Math.round(hours * 100) / 100,
incident_count: parseInt(count, 10),
}
}
return { mttr_hours: 0, incident_count: 0 }
}
| Tool | Purpose |
| --------------------------------- | -------------------------- |
| snow_query_incidents | Query incident records |
| snow_query_table | Advanced incident queries |
| snow_execute_script_with_output | Test incident scripts |
| snow_create_business_rule | Create incident automation |
// 1. Query open P1 incidents
await snow_query_incidents({
query: "priority=1^active=true",
fields: "number,short_description,assigned_to,opened_at",
})
// 2. Check incident metrics
await snow_execute_script_with_output({
script: `
var stats = calculateMTTR(gs.beginningOfThisMonth(), gs.endOfThisMonth(), {});
gs.info('MTTR: ' + stats.mttr_hours + ' hours');
`,
})
// 3. Find unassigned incidents
await snow_query_table({
table: "incident",
query: "active=true^assigned_toISEMPTY",
fields: "number,short_description,priority,assignment_group",
})
development
This skill should be used when the user asks to "App Engine Studio", "workspace builder", "custom workspace", "AES", "low code", "app development", "studio", or any ServiceNow App Engine Studio development.
tools
This skill should be used when the user asks to "create a widget", "build a widget", "service portal widget", "sp_widget", "fix widget", "widget not working", "ng-click not working", or any Service Portal widget development.
development
This skill should be used when the user asks to "create chatbot", "virtual agent", "VA topic", "NLU", "conversation", "chat flow", "topic block", or any ServiceNow Virtual Agent development.
development
This skill should be used when the user asks to "vendor", "supplier", "contract", "procurement", "SLA", "vendor risk", "vendor performance", or any ServiceNow Vendor Management development.