skills/admin/task-analysis/SKILL.md
Analyze task trends, identify bottlenecks, predict SLA breaches, and recommend workload redistribution
npx skillsauth add happy-technologies-llc/happy-servicenow-skills task-analysisInstall 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.
This skill provides comprehensive analysis of task data across ServiceNow to identify operational patterns and optimize work distribution. It covers:
task, sc_task, and planned_task tablestask_sla records and current task agingWhen to use: When managers need visibility into team workload distribution, when SLA compliance is trending downward, when planning capacity for upcoming projects, or when identifying systemic bottlenecks in task fulfillment.
Value proposition: Proactive task analysis prevents SLA breaches, balances workload across teams, and provides data-driven input for staffing and process improvement decisions.
itil, task_admin, assignment_group_manager, or admintask, sc_task, planned_task, task_sla, sys_user_group, and sys_user tablesGet a snapshot of active tasks across all task types.
Using MCP (Claude Code/Desktop):
Tool: SN-Execute-Background-Script
Parameters:
description: Task volume snapshot by type and state
script: |
var snapshot = { timestamp: new GlideDateTime().getDisplayValue(), task_types: [] };
var tables = ['incident', 'sc_task', 'change_request', 'problem', 'sc_req_item'];
tables.forEach(function(tableName) {
var typeData = { table: tableName, states: {} };
var ga = new GlideAggregate(tableName);
ga.addQuery('active', true);
ga.addAggregate('COUNT');
ga.groupBy('state');
ga.query();
var total = 0;
while (ga.next()) {
var state = ga.state.getDisplayValue();
var count = parseInt(ga.getAggregate('COUNT'));
typeData.states[state] = count;
total += count;
}
typeData.total_active = total;
snapshot.task_types.push(typeData);
});
gs.info(JSON.stringify(snapshot, null, 2));
Using REST API (for a specific task type):
GET /api/now/table/sc_task?sysparm_query=active=true&sysparm_fields=sys_id,number,state,assignment_group,assigned_to,priority,opened_at,sla_due&sysparm_limit=100&sysparm_display_value=true
Find groups with disproportionately high task volumes or aging tasks.
Using MCP:
Tool: SN-Execute-Background-Script
Parameters:
description: Identify bottleneck assignment groups
script: |
var bottlenecks = [];
var ga = new GlideAggregate('task');
ga.addQuery('active', true);
ga.addQuery('assignment_group', 'ISNOTEMPTY', '');
ga.addAggregate('COUNT');
ga.addAggregate('AVG', 'reassignment_count');
ga.groupBy('assignment_group');
ga.orderByAggregate('COUNT', 'DESC');
ga.query();
while (ga.next()) {
var groupId = ga.assignment_group.toString();
var count = parseInt(ga.getAggregate('COUNT'));
// Get average age of active tasks
var ageGa = new GlideAggregate('task');
ageGa.addQuery('active', true);
ageGa.addQuery('assignment_group', groupId);
ageGa.addAggregate('AVG', 'sys_mod_count');
ageGa.query();
var avgAge = 0;
if (ageGa.next()) {
avgAge = parseInt(ageGa.getAggregate('AVG', 'sys_mod_count'));
}
// Get group member count
var members = new GlideAggregate('sys_user_grmember');
members.addQuery('group', groupId);
members.addQuery('user.active', true);
members.addAggregate('COUNT');
members.query();
var memberCount = 0;
if (members.next()) memberCount = parseInt(members.getAggregate('COUNT'));
bottlenecks.push({
group: ga.assignment_group.getDisplayValue(),
active_tasks: count,
active_members: memberCount,
tasks_per_person: memberCount > 0 ? (count / memberCount).toFixed(1) : 'N/A',
avg_reassignments: parseFloat(ga.getAggregate('AVG', 'reassignment_count')).toFixed(1)
});
}
// Sort by tasks per person descending
bottlenecks.sort(function(a, b) {
return parseFloat(b.tasks_per_person) - parseFloat(a.tasks_per_person);
});
gs.info(JSON.stringify(bottlenecks.slice(0, 20), null, 2));
Analyze task SLA records to identify tasks at risk of breaching.
Using MCP:
Tool: SN-Query-Table
Parameters:
table_name: task_sla
query: stage=in_progress^has_breached=false^planned_end_time<=javascript:gs.hoursAgoEnd(-24)
fields: sys_id,task,task.number,task.short_description,task.assignment_group,task.assigned_to,task.priority,sla,planned_end_time,percentage,business_percentage,stage
limit: 50
order_by: planned_end_time
Using REST API:
GET /api/now/table/task_sla?sysparm_query=stage=in_progress^has_breached=false^planned_end_time<=javascript:gs.hoursAgoEnd(-24)&sysparm_fields=sys_id,task,task.number,task.short_description,task.assignment_group,task.assigned_to,task.priority,sla,planned_end_time,percentage,business_percentage&sysparm_limit=50&sysparm_display_value=true
Analyze breach risk by group:
Tool: SN-Execute-Background-Script
Parameters:
description: SLA breach risk analysis by assignment group
script: |
var riskAnalysis = [];
var ga = new GlideAggregate('task_sla');
ga.addQuery('stage', 'in_progress');
ga.addQuery('has_breached', false);
ga.addQuery('business_percentage', '>=', 75);
ga.addAggregate('COUNT');
ga.groupBy('task.assignment_group');
ga.orderByAggregate('COUNT', 'DESC');
ga.query();
while (ga.next()) {
var group = ga.getValue('task.assignment_group');
var atRisk = parseInt(ga.getAggregate('COUNT'));
// Count already breached
var breached = new GlideAggregate('task_sla');
breached.addQuery('stage', 'in_progress');
breached.addQuery('has_breached', true);
breached.addQuery('task.assignment_group', group);
breached.addAggregate('COUNT');
breached.query();
var breachedCount = 0;
if (breached.next()) breachedCount = parseInt(breached.getAggregate('COUNT'));
riskAnalysis.push({
group: ga.getDisplayValue('task.assignment_group'),
at_risk_75_plus: atRisk,
already_breached: breachedCount,
total_exposure: atRisk + breachedCount
});
}
gs.info(JSON.stringify(riskAnalysis, null, 2));
Examine workload per team member within an assignment group.
Using MCP:
Tool: SN-Execute-Background-Script
Parameters:
description: Individual workload analysis for assignment group
script: |
var groupId = '[group_sys_id]';
var workload = [];
var ga = new GlideAggregate('task');
ga.addQuery('active', true);
ga.addQuery('assignment_group', groupId);
ga.addQuery('assigned_to', 'ISNOTEMPTY', '');
ga.addAggregate('COUNT');
ga.groupBy('assigned_to');
ga.orderByAggregate('COUNT', 'DESC');
ga.query();
while (ga.next()) {
var userId = ga.assigned_to.toString();
// Get priority breakdown
var priorities = {};
var pa = new GlideAggregate('task');
pa.addQuery('active', true);
pa.addQuery('assigned_to', userId);
pa.addAggregate('COUNT');
pa.groupBy('priority');
pa.query();
while (pa.next()) {
priorities['P' + pa.priority.toString()] = parseInt(pa.getAggregate('COUNT'));
}
// Count tasks with SLA at risk
var slaRisk = new GlideAggregate('task_sla');
slaRisk.addQuery('task.assigned_to', userId);
slaRisk.addQuery('stage', 'in_progress');
slaRisk.addQuery('business_percentage', '>=', 75);
slaRisk.addAggregate('COUNT');
slaRisk.query();
var riskCount = 0;
if (slaRisk.next()) riskCount = parseInt(slaRisk.getAggregate('COUNT'));
workload.push({
user: ga.assigned_to.getDisplayValue(),
active_tasks: parseInt(ga.getAggregate('COUNT')),
priorities: priorities,
sla_at_risk: riskCount
});
}
// Unassigned tasks
var unassigned = new GlideAggregate('task');
unassigned.addQuery('active', true);
unassigned.addQuery('assignment_group', groupId);
unassigned.addQuery('assigned_to', 'ISEMPTY', '');
unassigned.addAggregate('COUNT');
unassigned.query();
var unassignedCount = 0;
if (unassigned.next()) unassignedCount = parseInt(unassigned.getAggregate('COUNT'));
var result = {
group: '[group_name]',
members: workload,
unassigned_tasks: unassignedCount
};
gs.info(JSON.stringify(result, null, 2));
Track task creation, completion, and backlog growth trends.
Using MCP:
Tool: SN-Execute-Background-Script
Parameters:
description: Weekly task trend analysis
script: |
var trends = [];
for (var i = 7; i >= 0; i--) {
var weekStart = gs.daysAgoStart(i * 7);
var weekEnd = gs.daysAgoEnd((i - 1) * 7);
var week = { period: 'Week -' + i, created: 0, closed: 0, backlog: 0 };
// Created
var created = new GlideAggregate('task');
created.addQuery('opened_at', '>=', weekStart);
created.addQuery('opened_at', '<=', weekEnd);
created.addAggregate('COUNT');
created.query();
if (created.next()) week.created = parseInt(created.getAggregate('COUNT'));
// Closed
var closed = new GlideAggregate('task');
closed.addQuery('closed_at', '>=', weekStart);
closed.addQuery('closed_at', '<=', weekEnd);
closed.addAggregate('COUNT');
closed.query();
if (closed.next()) week.closed = parseInt(closed.getAggregate('COUNT'));
week.net_change = week.created - week.closed;
trends.push(week);
}
// Current backlog
var backlog = new GlideAggregate('task');
backlog.addQuery('active', true);
backlog.addAggregate('COUNT');
backlog.query();
var currentBacklog = 0;
if (backlog.next()) currentBacklog = parseInt(backlog.getAggregate('COUNT'));
var result = {
current_backlog: currentBacklog,
weekly_trends: trends
};
gs.info(JSON.stringify(result, null, 2));
Based on the analysis, produce actionable recommendations.
Using MCP:
Tool: SN-Add-Work-Notes
Parameters:
table_name: sys_user_group
sys_id: [group_sys_id]
work_notes: |
=== TASK ANALYSIS & WORKLOAD REPORT ===
Group: Service Desk Team A
Date: 2026-03-19
CURRENT STATE:
- Active tasks: 87
- Unassigned: 12
- Members: 8 active
- Average per person: 10.9 tasks
WORKLOAD DISTRIBUTION:
- Alice Johnson: 18 tasks (5 P1/P2) - OVERLOADED
- Bob Smith: 15 tasks (3 P1/P2)
- Carol Davis: 12 tasks (2 P1/P2)
- Dan Wilson: 11 tasks (1 P1/P2)
- Eve Martinez: 10 tasks (2 P1/P2)
- Frank Lee: 8 tasks (0 P1/P2)
- Grace Chen: 7 tasks (1 P1/P2)
- Henry Patel: 6 tasks (0 P1/P2) - CAPACITY AVAILABLE
SLA RISK:
- 14 tasks at 75%+ SLA consumption (breach within 24 hours)
- 3 tasks already breached
- Highest risk: Alice Johnson (5 tasks at risk)
TRENDS (8 weeks):
- Creation rate: 45/week average (trending up +8%)
- Closure rate: 41/week average (stable)
- Backlog growing at ~4 tasks/week
RECOMMENDATIONS:
1. IMMEDIATE: Redistribute 5 tasks from Alice to Henry/Grace (capacity available)
2. IMMEDIATE: Assign 12 unassigned tasks prioritizing SLA-at-risk items
3. SHORT-TERM: Backlog growing - request 1 additional team member or cross-train
4. PROCESS: Investigate high reassignment rate (avg 2.3 per task) - routing rules may need tuning
| Tool | When to Use |
|------|-------------|
| SN-Query-Table | Query tasks, SLAs, groups, and assignments |
| SN-Get-Record | Retrieve individual task or group details |
| SN-NL-Search | Find tasks matching natural language descriptions |
| SN-Execute-Background-Script | Complex aggregations, trend analysis, workload calculations |
| SN-Add-Work-Notes | Post analysis reports and recommendations |
| Endpoint | Method | Purpose |
|----------|--------|---------|
| /api/now/table/task | GET | Query tasks across all types |
| /api/now/table/sc_task | GET | Query catalog tasks specifically |
| /api/now/table/planned_task | GET | Query planned/project tasks |
| /api/now/table/task_sla | GET | Analyze SLA status and breach risk |
| /api/now/table/sys_user_group | GET | Get assignment group details |
| /api/now/stats/task | GET | Use Stats API for server-side aggregation |
incident, sc_task) for type-specific analysis; use task for cross-type viewsbusiness_percentage from task_sla rather than calendar elapsed time for SLA analysisCause: Dashboard may use different filters (e.g., excluding certain states or task types) Solution: Compare the exact query used in the dashboard widget with your analysis query. Check for access controls that may filter results differently per user.
Cause: SLA definitions may have changed, or retroactive SLA attachments are affecting calculations
Solution: Check task_sla.sla reference to verify the correct SLA definition is attached. Review has_breached vs stage for accurate status.
Cause: Inactive users may still be group members, or users may have multiple group memberships
Solution: Filter sys_user_grmember with user.active=true and check for duplicate memberships.
Cause: No tasks were created or closed during certain periods, or data archiving removed historical records Solution: Include zero-count periods in trend output. Check if table rotation or archiving is configured for task tables.
Input: "Prepare task analysis data for the weekly ops review meeting"
Process: Run Steps 1, 2, 5, and 6 to generate a comprehensive snapshot with volume, bottlenecks, trends, and recommendations.
Input: "Which tasks are about to breach SLA in the next 24 hours?"
Tool: SN-Query-Table
Parameters:
table_name: task_sla
query: stage=in_progress^has_breached=false^planned_end_time<=javascript:gs.hoursAgoEnd(-24)^planned_end_time>=javascript:gs.beginningOfToday()
fields: task.number,task.short_description,task.assigned_to,task.assignment_group,planned_end_time,business_percentage
limit: 30
order_by: planned_end_time
Input: "I just took over Team B. Show me the current state of the team's work."
Process: Run Steps 2, 4, and 5 filtered to the specific group, generating a complete workload profile with per-person breakdown, SLA risks, and 8-week trends.
reporting/sla-analysis - Detailed SLA performance analysisreporting/trend-analysis - General trend analysis capabilitiesreporting/executive-dashboard - Executive-level reportingitsm/incident-lifecycle - Incident-specific task managementcatalog/request-fulfillment - Catalog task fulfillment workflowsadmin/workflow-creation - Automate task routing and escalationtesting
Manage supplier onboarding, qualification, performance monitoring, and offboarding with auditable lifecycle controls
tools
Identify emerging risks, prioritize intake signals, and route candidates into formal GRC risk assessment workflows
documentation
Screen inbound documents for completeness, policy risk, and routing readiness before extraction or case workflows
testing
Generate concise task summaries with status, timeline, blockers, SLA risk, and recommended next actions