| name | snu-artifacts |
| description | How sn-scriptsync maps ServiceNow artifacts to files: the instance/scope/table layout, naming conventions per artifact type, creating new artifacts, and the _map.json / structure.json files. Read this when creating, naming, or organizing ServiceNow files. |
SN ScriptSync — Artifacts & File Structure
Conventions for naming, creating, and organizing ServiceNow artifacts as local files.
File Naming Conventions
⚠️ CRITICAL: Do NOT Create Separate Field Files for Configuration
NEVER create separate files for configuration/metadata fields:
- ❌
MyBusinessRule.collection.js (table name - this is a STRING reference)
- ❌
MyBusinessRule.when.js (when to run - this is a STRING choice)
- ❌
MyBusinessRule.active.js (active status - this is a BOOLEAN)
- ❌
MyUIAction.table.js (table reference - this is a STRING)
- ❌
MyOperation.http_method.js (HTTP method - this is a STRING)
- ❌
MyScript.action_insert.js (action flag - this is a BOOLEAN)
These configuration fields belong in the creation payload ONLY, not as separate files.
✅ DO create files for actual script/code/content fields:
-
Script fields (contain executable code):
script → MyBusinessRule.script.js
operation_script → MyOperation.operation_script.js
client_script → MyWidget.client_script.js
server_script → MyWidget.server_script.js
processing_script → MyUIPage.processing_script.js
-
Template/HTML fields (contain markup):
template → MyWidget.template.html
html → MyUIPage.html
-
CSS fields (contain styles):
-
Special files:
option_schema.json (widget configuration schema)
demo_data.json (widget demo data)
link.js (widget link function)
Rule of thumb: If the field contains code, markup, or styles → create a file. If it's a configuration value (string, boolean, number, reference) → include in payload only.
Common Fields Reference Table
| Field Name | Type | Create File? | Example |
|---|
script | CODE | ✅ Yes | MyBR.script.js |
operation_script | CODE | ✅ Yes | MyOperation.operation_script.js |
client_script | CODE | ✅ Yes | MyWidget.client_script.js |
server_script | CODE | ✅ Yes | MyWidget.server_script.js |
processing_script | CODE | ✅ Yes | MyUIPage.processing_script.js |
template | MARKUP | ✅ Yes | MyWidget.template.html |
html | MARKUP | ✅ Yes | MyUIPage.html |
css | STYLES | ✅ Yes | MyWidget.css.scss |
link | CODE | ✅ Yes | MyWidget.link.js |
collection | CONFIG (string) | ❌ No | In payload: "collection": "incident" |
when | CONFIG (string) | ❌ No | In payload: "when": "before" |
active | CONFIG (boolean) | ❌ No | In payload: "active": "true" |
http_method | CONFIG (string) | ❌ No | In payload: "http_method": "GET" |
table | CONFIG (string) | ❌ No | In payload: "table": "incident" |
action_insert | CONFIG (boolean) | ❌ No | In payload: "action_insert": "true" |
action_update | CONFIG (boolean) | ❌ No | In payload: "action_update": "true" |
priority | CONFIG (number) | ❌ No | In payload: "priority": "100" |
order | CONFIG (number) | ❌ No | In payload: "order": "100" |
web_service_definition | CONFIG (reference) | ❌ No | In payload: "web_service_definition": "abc123..." |
Standard Scripts
- Use the artifact name with
.script.js extension
- Example:
HelloWorldUtils.script.js, DummyIncidentBR.script.js
Calculation Fields
- Use field name with
.calculation.js extension
- Example:
Foreign.calculation.js
Client Scripts for UI Actions
- Use artifact name with
.client_script_v2.js extension
- Example:
LargeBold.client_script_v2.js
Service Portal Widgets
- Widgets are folders containing multiple files
- File names:
template.html, client_script.js, css.scss, script.js, etc.
Creating New Artifacts
Important: Understanding Table Metadata
When creating a new artifact, the extension needs to understand the table structure:
Key Considerations:
- Mandatory Reference Fields: Some tables require references to other records (cannot be empty)
- Field Mappings: Different tables store scripts in different fields
- Required Setup: Some artifacts need parent records to exist first
Example: Scripted REST API (sys_ws_operation)
A sys_ws_operation record requires:
- Mandatory Reference:
web_service_definition field must reference a sys_ws_definition record
- Script Field: The script content is stored in the
operation_script field
- Parent Record Required: You must first create or have an existing REST API service definition
Workflow for Complex Artifacts:
- Extension detects new file
- Extension fetches table metadata from ServiceNow
- Extension analyzes mandatory fields and references
- Extension prompts user: "This requires a web_service_definition reference. Do you want to:
- Select an existing REST API service?
- Create a new REST API service?"
- User provides required information
- Extension creates the record with all required fields
- Extension updates
_map.json with the new sys_id
Working with Scoped Applications
⚠️ IMPORTANT: Do NOT create scope folders manually
Before creating files in a new scope folder:
- Sync at least one artifact first from ServiceNow for that scope
- This ensures the scope exists and the folder structure is correct
- The extension will create the scope folder automatically during the first sync
Why this matters:
- Scope names must match exactly with ServiceNow
- The scope must exist in the instance
- Incorrect scope names will cause sync failures
Correct Workflow:
- Create or identify a scope in ServiceNow (e.g.,
x_abc_my_app)
- Create at least one artifact in that scope in ServiceNow
- Use the extension to pull/sync that artifact
- The extension creates:
<instance>/x_abc_my_app/<table>/
- Now you can create new files in that scope folder
Creating Custom Tables
Use the typed create_table command — don't drive create_artifact against sys_db_object by hand. ServiceNow auto-creates the physical table plus its base sys_* fields (sys_id, sys_created_on, sys_updated_on, …); you only add your own columns.
Recipe:
create_table with name, label, optional scope and extends. With a non-global scope, the name is prefixed for you as <scope>_<name> (e.g. x_acme_myapp_project). The prefixed-vs-unprefixed naming is the usual stumbling block — let the command handle it, or pass an already-prefixed x_... name.
add_column for each field. Set display: true on the column you want as the display value (no separate update_record needed), and pass mandatory / default / choices inline so the column is usable in one call.
- Seed data rows with
rest_request POST /api/now/table/<name> (requires sn-scriptsync.restRequest.enabled). This is the blessed path for plain data rows — create_artifact requires fields.name, which is awkward when the display field isn't name.
Fallback (no typed command available): create the table via create_artifact/rest_request against sys_db_object using the full scoped name (x_<scope>_<name>); the base sys_* fields are created automatically; then add_column for the rest and set the display field.
Large / multi-field payloads (widgets)
When a payload has several large or multiline code fields — e.g. a widget's template / css / script / client_script — do not hand-build the JSON on a shell command line; the escaping is error-prone. Write the request body to a file with JSON.stringify (so newlines and quotes are encoded correctly) and send it with curl -d @body.json, or use the file transport. This applies to any artifact with multiline/large field values.
Verifying a widget preview (component-only screenshot)
To show just the rendered widget without a per-tab screenshot grant, combine activate_tab with the CDP capture_full_page selector:
activate_tab with openIfNotFound: true and waitForLoad: true (open/activate the widget preview).
capture_full_page with selector: ".my-widget" (or the widget's root class) for a clean, component-only screenshot — no per-tab grant required.
(capture_full_page uses the browser debugger — preflight with get_capabilities → cdp.available.)
Step-by-Step: Creating Simple Artifacts
For simple artifacts like Script Includes (no mandatory references):
Step 1: Create the file in the correct location
<your_instance>/global/sys_script_include/MyNewUtils.script.js
Or for a scoped app (after syncing at least one artifact):
<your_instance>/<your_scope>/sys_script_include/MyNewUtils.script.js
Step 2: Write your code
var MyNewUtils = Class.create();
MyNewUtils.prototype = {
initialize: function() {
},
myFunction: function() {
return 'Hello World';
},
type: 'MyNewUtils'
};
Step 3: Save the file
The sn-scriptsync extension will:
- Detect the new file
- Fetch table metadata to check for mandatory fields
- Create the record in ServiceNow (prompting for required info if needed)
- Automatically update
_map.json with the new sys_id
⚠️ IMPORTANT: Only create the .script.js file
- Do NOT create separate files like
.collection.js, .when.js, .active.js
- The extension will prompt for required fields (like
collection for Business Rules)
- OR use
create_artifact command to include all fields in one payload
Common Table Requirements
| Table | Script Field | Mandatory References | Notes |
|---|
sys_script_include | script | None | Simple creation |
sys_script | script | collection (table name) | Must specify which table |
sys_ws_operation | operation_script | web_service_definition | Needs parent REST API |
sys_ui_action | script | table (table name) | Must specify which table |
sys_script_client | script | table (table name) | Must specify which table |
sp_widget | Multiple files | None | Widget folder structure |
rm_story | N/A | None | See rm_story specific guidance below |
rm_story (Story) Table Specifics
Key Fields:
name - Required by create_artifact (can be same as short_description)
short_description - The story title/summary
description - Detailed description (plain text)
acceptance_criteria - HTML field - use HTML formatting, not markdown
state - Story state (see values below)
priority - Priority level (1-4)
State Values:
| State | Value | Description |
|---|
| Draft | -6 | Initial state, not ready for work |
| Ready | 1 | Ready for development |
| Work in Progress | 2 | Currently being worked on |
| Ready for Testing | -7 | Development complete, ready for QA |
| Testing | -8 | Currently being tested |
| Complete | 3 | Story is done |
| Cancelled | 4 | Story was cancelled |
⚠️ IMPORTANT: acceptance_criteria is an HTML field!
Use HTML tags for formatting, NOT markdown:
<b>Acceptance Criteria:</b>
<ul>
<li>Widget displays correctly</li>
<li>Score tracking works</li>
<li>No console errors</li>
</ul>
<b>Definition of Done:</b>
<ul>
<li>Code reviewed</li>
<li>Unit tests pass</li>
</ul>
<!-- ❌ INCORRECT - Markdown won't render -->
**Acceptance Criteria:**
- Widget displays correctly
- Score tracking works
Example: Creating a Story
{
"command": "create_artifact",
"params": {
"table": "rm_story",
"scope": "global",
"fields": {
"name": "Implement User Dashboard Widget",
"short_description": "Implement User Dashboard Widget",
"description": "Create a Service Portal widget that displays user statistics and recent activity.",
"acceptance_criteria": "<b>Acceptance Criteria:</b><ul><li>Widget shows user stats</li><li>Responsive design</li></ul><b>Definition of Done:</b><ul><li>Code reviewed</li><li>Tested in dev</li></ul>",
"state": "1",
"priority": "2"
}
}
}
Updating Story State:
{
"command": "update_record",
"params": {
"table": "rm_story",
"sys_id": "abc123...",
"field": "state",
"content": "-7"
}
}
Note: State values are strings (e.g., "-7" not -7)
Handling Mandatory References
When the extension detects a mandatory reference field:
The extension should:
- Query ServiceNow for available reference options
- Present choices to the user
- Allow creation of a new reference record if needed
- Validate the reference exists before creating the artifact
The extension should NOT:
- Set reference fields to empty strings
- Create records without required references
- Assume default values for mandatory fields
Fetching Table Metadata
Before creating a new record, the extension should:
-
Query the ServiceNow API to get table dictionary information:
GET /api/now/table/sys_dictionary?sysparm_query=name=<table_name>^ORDERBYelement
-
Analyze mandatory fields: Check for fields where mandatory=true
-
Identify reference fields: Check reference field for reference table names
-
Map script fields: Different tables use different field names:
- Most tables:
script
- REST API Operations:
operation_script
- UI Pages: Multiple fields (
html, client_script, processing_script)
-
Consult ServiceNow documentation if needed for complex tables: