script-include-patterns skill
✓ VerifiedWrite and manage ServiceNow Script Includes using Class.create, AbstractAjaxProcessor, and inheritance patterns.
- GitHub stars
- 77
- Files
- 1
- Last commit
- Oct 20, 2026
- License
- Apache-2.0
- Allowed tools
- —
What does the script-include-patterns skill do?
script-include-patterns writes and manage ServiceNow Script Includes using Class.create, AbstractAjaxProcessor, and inheritance patterns.
Summary generated from the skill's SKILL.md.
About the script-include-patterns skill
Developing reusable server-side JavaScript libraries for ServiceNow is the primary function of this skill. It assists developers in writing and managing various types of Script Includes, including standard utilities, client-callable APIs for GlideAjax, and on-demand lazy loading classes. The skill supports complex architectural patterns such as inheritance via Object.extendsObject and specific implementations for scoped applications.
An agent should load this skill when a developer needs to build or modify ServiceNow logic. It provides specific tools to automate the development lifecycle, such as snow_create_script_include for generating new classes, snow_artifact_manage for finding or updating existing code, and snow_execute_script for testing logic. By following ES5 standards, it ensures compatibility with the ServiceNow environment while helping maintain clean code through structured patterns like AbstractAjaxProcessor for client-server communication.
What an agent can do with it
- 1Build client-callable APIsDevelop a class that extends AbstractAjaxProcessor to allow client scripts to communicate with the server via GlideAjax.
- 2Implement class inheritanceCreate a derived class that inherits functionality from a base task utility class.
Written from the skill's SKILL.md. Every use case is checked against a quote from it.
How to install the script-include-patterns skill
Each command copies the skill folder into the client's skills directory. Restart the client or start a new session to load it.Install the script-include-patterns skill in Claude Code
~/.claude/skills/script-include-patterns/SKILL.md
$ npx degit serac-labs/serac/packages/skills/script-include-patterns ~/.claude/skills/script-include-patternsInstall the script-include-patterns skill in Claude Code (project)
.claude/skills/script-include-patterns/SKILL.md
$ npx degit serac-labs/serac/packages/skills/script-include-patterns .claude/skills/script-include-patternsInstall the script-include-patterns skill in Codex
~/.agents/skills/script-include-patterns/SKILL.md
$ npx degit serac-labs/serac/packages/skills/script-include-patterns ~/.agents/skills/script-include-patternsInstall the script-include-patterns skill in Gemini CLI
~/.gemini/skills/script-include-patterns/SKILL.md
$ npx degit serac-labs/serac/packages/skills/script-include-patterns ~/.gemini/skills/script-include-patternsInstall the script-include-patterns skill in Claude.ai
npx degit serac-labs/serac/packages/skills/script-include-patterns script-include-patterns && zip -r script-include-patterns.zip script-include-patterns # claude.ai → Customize → Skills → + → Create skill → Upload a skill → script-include-patterns.zip
Automated checks
Ran Nov 14, 2026Full report →Passed our automated checks. That is not a security audit: read the scripts before you let an agent run them. How checks work
- Source repository linked and reachableserac-labs/serac/packages/skills/script-include-patterns is public and reachablegithub.com/serac-labs/serac/tree/HEAD/packages/skills/script ↗Pass
- Open source license (OSI)Apache-2.0spdx.org/licenses/Apache-2.0.html ↗Pass
- Commit or release in the last yearLast commit 2026-10-20github.com/serac-labs/serac/commits ↗Pass
- No download-and-run or credential theft in scriptsNo scripts in the skill folderPass
- No hidden instructions in SKILL.mdNo override phrases, safeguard switches, credential requests or hidden charactersgithub.com/serac-labs/serac/blob/HEAD/packages/skills/script ↗Pass
- Pre-approved tools are scopedNo pre-approved tools; the agent asks before using onegithub.com/serac-labs/serac/blob/HEAD/packages/skills/script ↗Pass
- SKILL.md follows the Agent Skills formatthe description does not say when to use the skillgithub.com/serac-labs/serac/blob/HEAD/packages/skills/script ↗Finding
SKILL.md
View on GitHubScript Include Patterns for ServiceNow
Script Includes are reusable server-side JavaScript libraries that can be called from any server-side script.
Script Include Types
| Type | Use Case | Client Callable |
|---|---|---|
| Standard | Server-side utilities | No |
| Client Callable | GlideAjax from client | Yes |
| On-Demand | Lazy loading | No |
| AbstractAjaxProcessor | Client-server communication | Yes |
Standard Script Include (ES5)
// Basic utility class
var IncidentUtils = Class.create()
IncidentUtils.prototype = {
initialize: function () {
this.LOG_PREFIX = "[IncidentUtils] "
},
/**
* Get incident by number
* @param {string} number - Incident number (INC0010001)
* @returns {GlideRecord|null} - Incident record or null
*/
getByNumber: function (number) {
var gr = new GlideRecord("incident")
gr.addQuery("number", number)
gr.query()
if (gr.next()) {
return gr
}
return null
},
/**
* Calculate priority based on impact and urgency
* @param {number} impact - Impact value (1-3)
* @param {number} urgency - Urgency value (1-3)
* @returns {number} - Calculated priority (1-5)
*/
calculatePriority: function (impact, urgency) {
var matrix = {
"1-1": 1,
"1-2": 2,
"1-3": 3,
"2-1": 2,
"2-2": 3,
"2-3": 4,
"3-1": 3,
"3-2": 4,
"3-3": 5,
}
var key = impact + "-" + urgency
return matrix[key] || 4
},
/**
* Get open incidents for user
* @param {string} userSysId - User sys_id
* @returns {Array} - Array of incident objects
*/
getOpenIncidentsForUser: function (userSysId) {
var incidents = []
var gr = new GlideRecord("incident")
gr.addQuery("caller_id", userSysId)
gr.addQuery("active", true)
gr.orderByDesc("opened_at")
gr.query()
while (gr.next()) {
incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
state: gr.state.getDisplayValue(),
priority: gr.priority.getDisplayValue(),
})
}
return incidents
},
type: "IncidentUtils",
}
Client Callable Script Include (ES5)
// Extends AbstractAjaxProcessor for GlideAjax calls
var IncidentAjax = Class.create()
IncidentAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, {
/**
* Get incident details - callable from client
* Client calls: new GlideAjax('IncidentAjax').addParam('sysparm_name', 'getIncidentDetails')
*/
getIncidentDetails: function () {
var incidentId = this.getParameter("sysparm_incident_id")
var result = {}
var gr = new GlideRecord("incident")
if (gr.get(incidentId)) {
result.success = true
result.number = gr.getValue("number")
result.short_description = gr.getValue("short_description")
result.state = gr.state.getDisplayValue()
result.priority = gr.priority.getDisplayValue()
result.assigned_to = gr.assigned_to.getDisplayValue()
result.assignment_group = gr.assignment_group.getDisplayValue()
} else {
result.success = false
result.message = "Incident not found"
}
return JSON.stringify(result)
},
/**
* Search incidents by keyword
*/
searchIncidents: function () {
var keyword = this.getParameter("sysparm_keyword")
var limit = parseInt(this.getParameter("sysparm_limit"), 10) || 10
var incidents = []
var gr = new GlideRecord("incident")
gr.addQuery("short_description", "CONTAINS", keyword)
gr.addOrCondition("description", "CONTAINS", keyword)
gr.addQuery("active", true)
gr.setLimit(limit)
gr.orderByDesc("opened_at")
gr.query()
while (gr.next()) {
incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
})
}
return JSON.stringify(incidents)
},
/**
* Check if user can update incident
*/
canUserUpdate: function () {
var incidentId = this.getParameter("sysparm_incident_id")
var userId = gs.getUserID()
var gr = new GlideRecord("incident")
if (gr.get(incidentId)) {
// Check if user is assigned or in assignment group
var canUpdate =
gr.getValue("assigned_to") === userId || this._isUserInGroup(userId, gr.getValue("assignment_group"))
return JSON.stringify({ canUpdate: canUpdate })
}
return JSON.stringify({ canUpdate: false })
},
_isUserInGroup: function (userId, groupId) {
var member = new GlideRecord("sys_user_grmember")
member.addQuery("user", userId)
member.addQuery("group", groupId)
member.query()
return member.hasNext()
},
type: "IncidentAjax",
})
Client-Side GlideAjax Call (ES5)
// Client script calling Script Include
function getIncidentDetails(incidentSysId, callback) {
var ga = new GlideAjax("IncidentAjax")
ga.addParam("sysparm_name", "getIncidentDetails")
ga.addParam("sysparm_incident_id", incidentSysId)
ga.getXMLAnswer(function (answer) {
var result = JSON.parse(answer)
callback(result)
})
}
// Usage in client script
getIncidentDetails(g_form.getUniqueValue(), function (incident) {
if (incident.success) {
g_form.addInfoMessage("Incident: " + incident.number)
} else {
g_form.addErrorMessage(incident.message)
}
})
Inheritance Pattern (ES5)
// Base class
var TaskUtils = Class.create()
TaskUtils.prototype = {
initialize: function (tableName) {
this.tableName = tableName || "task"
},
getByState: function (state) {
var records = []
var gr = new GlideRecord(this.tableName)
gr.addQuery("state", state)
gr.query()
while (gr.next()) {
records.push(this._toObject(gr))
}
return records
},
_toObject: function (gr) {
return {
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
state: gr.getValue("state"),
}
},
type: "TaskUtils",
}
// Derived class
var IncidentUtilsExtended = Class.create()
IncidentUtilsExtended.prototype = Object.extendsObject(TaskUtils, {
initialize: function () {
TaskUtils.prototype.initialize.call(this, "incident")
},
getP1Incidents: function () {
var incidents = []
var gr = new GlideRecord("incident")
gr.addQuery("priority", 1)
gr.addQuery("active", true)
gr.query()
while (gr.next()) {
var obj = this._toObject(gr)
obj.caller = gr.caller_id.getDisplayValue()
incidents.push(obj)
}
return incidents
},
type: "IncidentUtilsExtended",
})
Scoped Script Include (ES5)
// In scoped application: x_myapp
var MyAppUtils = Class.create()
MyAppUtils.prototype = {
initialize: function () {
this.APP_SCOPE = "x_myapp"
},
/**
* Get application property
* @param {string} name - Property name (without scope prefix)
*/
getAppProperty: function (name) {
return gs.getProperty(this.APP_SCOPE + "." + name)
},
/**
* Log with application prefix
*/
log: function (message, source) {
gs.info("[" + this.APP_SCOPE + "][" + (source || "MyAppUtils") + "] " + message)
},
/**
* Access cross-scope table safely
*/
getGlobalUser: function (userId) {
var gr = new GlideRecord("sys_user")
if (gr.get(userId)) {
return {
name: gr.getValue("name"),
email: gr.getValue("email"),
}
}
return null
},
type: "MyAppUtils",
}
MCP Tool Integration
Available Script Include Tools
| Tool | Purpose |
|---|---|
snow_create_script_include |
Create new Script Include |
snow_artifact_manage (action='find') |
Find existing Script Includes |
snow_artifact_manage (action='update') |
Modify Script Include code |
snow_execute_script |
Test Script Include |
Example Workflow
// 1. Create Script Include
await snow_create_script_include({
name: "IncidentUtils",
script: "/* Script Include code */",
client_callable: false,
description: "Incident utility functions",
})
// 2. Test the Script Include
await snow_execute_script({
script: `
var utils = new IncidentUtils();
var incident = utils.getByNumber('INC0010001');
gs.info('Found: ' + (incident ? incident.number : 'null'));
`,
})
Best Practices
- Single Responsibility - One class, one purpose
- Meaningful Names - IncidentUtils not Utils
- Document Methods - JSDoc comments
- Error Handling - Try-catch with logging
- Private Methods - Prefix with underscore
- No Side Effects - Initialization should not modify data
- Testable - Write methods that can be unit tested
- ES5 Only - No const, let, arrow functions, template literals
Files in this skill
1script-include-patterns skill questions
How do I install the script-include-patterns skill in Claude Code?
Run npx degit serac-labs/serac/packages/skills/script-include-patterns ~/.claude/skills/script-include-patterns. Claude Code loads skills from ~/.claude/skills (all projects) or .claude/skills (one project) and uses a skill when its description matches the task.
Which clients can use the script-include-patterns skill?
Any client that reads the Agent Skills format: Claude Code, Codex, Gemini CLI and claude.ai (upload as a ZIP). Scripts in the skill run only where the client allows code execution.
What are the different types of Script Includes in ServiceNow?
Script Includes can be Standard (server-side utilities), Client Callable (for GlideAjax), On-Demand (lazy loading), or AbstractAjaxProcessor (for client-server communication).
How do I implement inheritance in a ServiceNow Script Include?
You can use the Object.extendsObject method to allow a derived class to inherit from a base class.
What coding standards should be followed when writing Script Includes?
Developers should use ES5 syntax (avoiding const, let, or arrow functions), follow the single responsibility principle, use meaningful names, and prefix private methods with an underscore.