AI Agent Support
Use AI coding assistants like Cursor, GitHub Copilot, and Windsurf with sn-scriptsync for automated ServiceNow development.
Last updated: January 24, 2026
Version 4.0 of sn-scriptsync brings native AI coding assistant support. Changes made by AI tools are automatically detected and synced to your ServiceNow instance.
Supported AI Tools
sn-scriptsync works with any tool that modifies files on disk:
- Cursor (with Claude, GPT-4, etc.)
- GitHub Copilot
- Windsurf
- Cline / Claude Dev
- Aider
- Any other AI coding assistant or external editor
How It Works
- Automatic detection — File changes are detected via file system watcher
- Smart batching — Changes are intelligently grouped and deduplicated for efficiency
- Multi-field batching — Multiple field changes on the same record are combined into a single API call
- Configurable delay — The
syncDelaysetting controls sync frequency (default: 30 seconds, set to 0 to disable)
Ctrl+S / Cmd+S in a file syncs it immediately, bypassing the queue. Saves VS Code makes in other ways (Save All, a rename across files, auto save, another extension) wait in Pending Saves and are never auto-synced; see Which Saves Sync.
Pending Saves Queue
A tree view panel shows files waiting to sync:
- Pause/Resume queue functionality
- Sync Now button for immediate sync, including saves held because they were not made with Ctrl+S / Cmd+S
- Remove individual files from the queue
AI Agent Instructions
When you start sn-scriptsync, an agentinstructions.md file is written to your workspace root. It contains guidelines for AI agents to work effectively with sn-scriptsync — file-structure patterns, Agent API documentation, and ServiceNow best practices.
Recommended: import or reference it instead of renaming. Keeping agentinstructions.md as the single source of truth lets the extension keep it up to date automatically when you upgrade. Point your tool's own rules file at it:
- Cursor → in
.cursorrules(or a file under.cursor/rules/) add:Follow the rules in @agentinstructions.md - Claude → in
CLAUDE.mdadd:@agentinstructions.md - GitHub Copilot → copy into
.github/copilot-instructions.md(Copilot has no import; see auto-refresh below) - Windsurf → copy into
.windsurfrules(no import; see auto-refresh below)
Keeping the docs and skills up to date
agentinstructions.md and the on-demand skills under agentrules/skills/ are regenerated by the extension on every start and re-synced whenever their version is newer than the copy in your workspace. To pull the latest, update the sn-scriptsync extension and reload VS Code (or run ServiceNow ScriptSync: Enable). Renamed or removed skills are cleaned up automatically, and any file you authored yourself is never touched.
Prefer your own agent instructions?
If you maintain your own CLAUDE.md / AGENTS.md / .cursorrules and don't want the managed reference block added to them, set sn-scriptsync.agentInstructions.autoUpdate to false. The extension then stops injecting and refreshing that block inside your files — but still keeps agentinstructions.md and agentrules/skills/ current, so you can reference them on demand yourself (for example @agentinstructions.md, or point your agent at a specific agentrules/skills/<name>/SKILL.md).
Creating New Artifacts with AI
AI agents can create new ServiceNow artifacts by creating files in the correct folder structure:
{instance}/{scope}/{table}/{name}.{field}.{extension}
For example, to create a new Script Include:
myinstance/global/sys_script_include/MyNewUtils.script.js
The extension will automatically detect the new file, create the record in ServiceNow, and update _map.json with the new sys_id.
Agent API
For advanced integrations, sn-scriptsync exposes a programmatic Agent API so AI tools can drive ServiceNow directly. There are two transports for the same set of commands:
- HTTP API (recommended) — a local HTTP server, the preferred, event-driven transport.
- File-based API (legacy) — a folder queue of JSON files, kept for backward compatibility.
HTTP API (recommended)
When the extension starts it launches a local HTTP server bound to 127.0.0.1, preferring the fixed port 1977 (it falls back to a random free port only when 1977 is taken), secured with a per-session token. Send commands with a single POST /api call, passing the token in the X-Agent-Token header:
curl -s -X POST http://127.0.0.1:1977/api \
-H "X-Agent-Token: <token>" \
-H "Content-Type: application/json" \
-d '{ "id": "chk_1", "command": "check_connection", "instance": "dev12345" }'
Connect any agent in two lines (Pro)
Everything above — file-watcher sync, agentinstructions.md, and the Agent API via the workspace port file — works free: agents inside your editor (Cursor, Copilot, or a CLI agent started in the sync workspace) need no license. Pro adds connect-from-anywhere for external terminal agents (Claude Code, Codex): a well-known per-user port file plus a paste-anywhere instruction snippet, so agents find ScriptSync without knowing the workspace.
Run sn-scriptsync: Copy agent connect instructions from the VS Code command palette (or click Connect an agent in the SN Utils helper tab; the block also appears in the helper tab's sync log when ScriptSync connects) and paste the snippet into any AI agent's instructions — a global CLAUDE.md, AGENTS.md, a Devin playbook, any system prompt. Requires an active SN Utils Pro, Trial, or Enterprise license in the connected browser (the global port file is only written then). The agent then needs no workspace files at all:
GET http://127.0.0.1:1977/api/instructions— full usage docs, served by the running extension itself (no auth), so they always match the installed version.GET /api/skillsand/api/skills/<name>serve the on-demand skills the same way.- Token (and the actual port, if 1977 was taken):
~/.sn-scriptsync/agent-port.json.
Discovering the endpoint
The extension publishes the live endpoint to two places: ~/.sn-scriptsync/agent-port.json (well-known per-user location, readable from any directory, written with user-only permissions — Pro: only written while a Pro/Trial/Enterprise license is connected) and .vscode/sn-agent-port.json in your workspace (always written, free):
{
"port": 1977,
"token": "4f9a…hex…",
"pid": 68861,
"apiVersion": 7,
"startedAt": 1730000000000
}
Treat these files as a hint and validate before trusting them — a copy can be stale after a crash or (the workspace copy) a machine move or cloud-sync. Do this every session and never cache the port/token:
- Read
port,token, andpidfrom~/.sn-scriptsync/agent-port.json(fall back to.vscode/sn-agent-port.jsonon older versions). - Call
GET http://127.0.0.1:<port>/api/health(no auth required). - Trust the endpoint only if the request succeeds (HTTP 200),
health.pidmatches the file'spid, andhealth.apiVersionis one you support. - If any check fails (no file, connection refused, pid/version mismatch), fall back to the file-based API.
- Read the available commands from
health.commands[]rather than hard-coding them.
curl -s http://127.0.0.1:1977/api/health
# → { "status": "success", "apiVersion": 7, "commands": [ … ], "pid": 68861 }
Request and response shape
Every authenticated request is a POST /api with a JSON body containing a command, an optional id (auto-generated if omitted), an optional instance, and command-specific params:
{ "id": "upd_1", "command": "update_record", "instance": "dev12345",
"params": { "table": "sys_script_include", "sys_id": "…", "field": "script", "content": "gs.info('hi');" } }
Successful responses echo the id/command and carry a result:
{ "id": "upd_1", "command": "update_record", "status": "success",
"result": { "success": true, "table": "sys_script_include", "sys_id": "…", "field": "script" },
"timestamp": 1730000001235 }
Errors return status: "error" with a structured code:
{ "status": "error", "code": "E_BROWSER_DISCONNECTED", "error": "No browser helper tab is connected." }
| Code | HTTP | Meaning |
|---|---|---|
E_INVALID_PARAMS / E_INVALID_REQUEST | 400 | Malformed request or missing params |
E_UNAUTHORIZED | 401 | Missing/invalid X-Agent-Token |
E_UNKNOWN_COMMAND | 404 | No such command |
E_INSTANCE_REQUIRED / E_INSTANCE_NOT_FOUND | 422 | Instance not resolvable |
E_DISABLED | 423 | Feature disabled via settings |
E_PAUSED | 423 | Agent access is paused via the pause switch in the SN Utils helper tab — resume it there |
E_SERVER_NOT_RUNNING / E_BROWSER_DISCONNECTED | 503 | Can't reach ServiceNow |
E_TIMEOUT | 504 | Round-trip exceeded the deadline |
E_ACL / E_TOKEN_EXPIRED | 502 | ServiceNow rejected the request |
E_INTERNAL | 500 | Unexpected error |
Available Commands
The same commands work over both transports. The authoritative list for your installed version is always health.commands[].
Connection & sync
| Command | Description |
|---|---|
check_connection | Verify the server is running and a browser tab is connected; also reports which SN Utils build is on the other end (helper.debuggerAvailable, tier) |
get_capabilities | Preflight what the helper tab can do right now — license tier, whether the browser debugger (CDP) is usable (cdp.available), and which write/create/delete permission gates are enabled |
get_instance_info | Resolved instance name and connection flags |
get_sync_status | Inspect the pending-file sync queue |
sync_now | Flush all pending files to ServiceNow immediately |
get_last_error | Read the last remote sync error |
clear_last_error | Clear the recorded error |
Records
| Command | Description |
|---|---|
create_artifact | Create a record from a fields payload (executes immediately; needs the Create permission) |
pull_records | Pull records from ServiceNow and store code fields into canonical local files with _map.json tracking (alias: pull_artifacts) |
pull_scope | Pull every scriptable artifact of one application scope into canonical local files in one call, paged past the Table API limits and refreshable (use pull_records for global or ad-hoc selections) |
get_record | Fetch a single record by table and sys_id |
update_record | Update a single field on an existing record (needs the Update permission) |
update_record_batch | Update multiple fields on one record in a single round-trip (needs the Update permission) |
get_table_metadata | Fetch column metadata for a table (mandatory fields, types, references) |
check_name_exists_remote | Ask ServiceNow whether a record name already exists |
sdk_deploy | Build and install a NOW SDK (Fluent) app with the browser session after the user confirms in the helper tab; stops when the app changed on the instance since the last sync unless force is set (Pro; see Deploy NOW SDK Apps) |
sdk_pull | Pull changes made on the instance into a NOW SDK project, applied when git can show and undo them; dryRun lists them (Pro) |
Query
| Command | Description |
|---|---|
query_records | Run an encoded query against any table |
get_parent_options | Fetch reference options (e.g. parent services for a REST endpoint) |
code_search | Run the SN Utils GraphQL field-index code search across script tables and return structured matches (Pro feature — needs an active SN Utils Pro/Trial/Enterprise license in the connected browser) |
Local files
| Command | Description |
|---|---|
list_tables | List table folders under the instance |
list_artifacts | List artifact files in a table folder |
check_name_exists | Look up a name in local _map.json files |
get_file_structure | Return the file-naming convention and code fields per table |
validate_path | Validate a proposed file path against the convention |
Browser
| Command | Description |
|---|---|
open_in_browser | Open a record/widget form in the connected browser |
activate_tab | Find a tab by URL pattern and activate (or open) it |
refresh_preview | Refresh widget/portal preview tabs |
take_screenshot | Capture a ServiceNow URL/tab to screenshots/. Picks the best available path: granted tab, else silently via the Chrome debugger (Debug edition + Pro + debugger setting; result says capturedVia: "debugger"), else asks for the one-time icon-click grant |
upload_attachment | Attach a file (disk path or base64) to a record — inserts a sys_attachment row, so it needs the Create permission |
run_slash_command | Execute an SN Utils slash command (e.g. /tn, /bg) |
switch_context | Switch update set, application scope, or domain |
Browser debugger (CDP) — needs the Debug edition build + a Pro subscription, off by default
These commands drive the connected ServiceNow tab through the Chrome DevTools Protocol (chrome.debugger) for things the normal content-script bridge can't do — network bodies, console errors, beyond-viewport screenshots, and captured dialog text. They are an escalation: reach for the g_form / REST commands first.
| Command | Description |
|---|---|
start_network_capture | Start recording network traffic (method/URL/headers and, by default, response bodies). Supports urlFilter, includeBodies, includeTypes, maxEntries, maxBodyBytes |
stop_network_capture | Stop the capture and return the recorded requests; detaches the debugger unless another capture/handler is still active |
start_console_capture | Start capturing console.* output, log entries, and uncaught exceptions |
stop_console_capture | Stop the capture and return the collected entries (kind: console / log / exception) |
capture_full_page | Full-page (entire scrollable page) or single-element (selector) screenshot saved under screenshots/. Needs no per-tab grant, unlike take_screenshot |
set_dialog_handler | Auto-answer and record native confirm() / alert() / prompt() / beforeunload dialogs (autoAccept, promptText). Persists across navigations |
clear_dialog_handler | Remove the dialog handler and return the dialogs intercepted while it was active |
debugger_detach | Force-detach the debugger and drop the banner — a safety net if a session was left open |
A typical "why did that request fail?" loop:
start_network_capture (urlFilter: "/api/now") start_console_capture → run_ui_action / click_element / navigate (reproduce the action) stop_network_capture (inspect status + response body) stop_console_capture (inspect client-side errors)
All browser-debugger commands share these error codes: E_PRO_REQUIRED, E_DISABLED, E_CDP_UNAVAILABLE, E_DEBUGGER_BUSY, E_NO_TAB, E_BROWSER_DISCONNECTED, E_TIMEOUT (plus E_NO_ELEMENT for capture_full_page with a selector).
File-based API (legacy)
Human Review Queue & Security Gates
Starting with ScriptSync 4.8.0 and SN Utils 10.1.7.5, high-risk agent operations and instance authorizations are governed interactively in the SN Utils ScriptSync Helper tab:
1. Two-Phase Human Review Queue
When an AI agent requests a high-impact operation (such as run_background_script or delete_record), the command is held in a Review Queue:
- An interactive review card appears in the helper tab with the code payload or delete target.
- A 5-minute expiry countdown timer starts, the page title alerts you, and the favicon flashes.
- You can inspect the operation, enter optional feedback, and click Approve once or Reject.
- If rejected or timed out, the agent receives an immediate, structured
E_USER_REJECTEDorE_REVIEW_EXPIREDresponse.
2. Per-Instance Security Permissions
In the helper tab's Agent Access tab, you can set each capability separately per instance:
- Background scripts: Run background scripts (also covers the
delete_applicationcascade). - Delete records: Delete records via the API, REST
DELETE, and delete verbs on a form. - Create artifacts: Create records and artifacts:
create_record,create_artifact,create_application,create_table,add_column, attachment uploads, and NOW SDK app deploys (sdk_deploy). - Update records: Change fields on records that already exist:
update_record,update_record_batch, and committing an open form withrun_ui_action. - REST writes: Direct
POST/PUT/PATCHcalls throughrest_request. - Browser debugger: Capture network and console logs and screenshots.
Each one has three states rather than a simple on/off: off refuses the command outright, approve holds it in the Review Queue above until you approve it, and auto lets it run without asking. This is what lets you leave dev on auto while production sits on approve or off.
The permission an instance has not granted is refused, so a command an agent cannot run comes back as a structured E_DISABLED naming the permission. Agents are instructed to tell you what to enable rather than looking for another route to the same write. Settings persist across sessions and synchronize live with connected agents and editor instances.
Standalone CLI & MCP Server (@snutils/snu)
AI agents outside VS Code (Claude Code, terminal agents, standalone scripts) can use the official @snutils/snu CLI and MCP server:
# Run standalone SN Utils agent commands npx -y @snutils/snu@latest context npx -y @snutils/snu@latest pull sys_script "nameSTARTSWITHincident" --limit 10 npx -y @snutils/snu@latest pull-scope x_acme_app npx -y @snutils/snu@latest query incident "active=true" --limit 5 npx -y @snutils/snu@latest search "GlideRecord"
To use it as an MCP server in Claude Code, Cursor, Claude Desktop, or Windsurf, one command detects your installed AI tools and writes the configuration for you:
npx -y @snutils/snu@latest setup
Prefer to configure manually? snu setup --print shows the copy-paste blocks for every client, or add this entry yourself:
{
"mcpServers": {
"sn-utils": {
"command": "npx",
"args": ["--yes", "--prefer-online", "@snutils/snu@latest", "--mcp"]
}
}
}
The configuration is static and secret-free: the bridge port and auth token are discovered at call time from the local port file, so the same entry works for every user and machine, and a project-scoped config file is safe to commit and share with your team.
Staying connected after a restart
The bridge keeps your ServiceNow session tokens in memory only. A restarted bridge, a reloaded helper tab, or a laptop waking from sleep used to mean running /token again on every instance before an agent could continue.
The helper tab can take care of this for a limited time:
- Run
/tokenon the instance yourself. That tells the helper tab that the bridge on your machine is yours, and starts a 20-hour window for that instance. - Within that window, the helper tab gets a fresh token by itself when it reconnects to the same bridge, or when an agent's request fails because its token went stale. You see a Session token refreshed automatically row in the Activity Log.
- After 20 hours, automatic refresh stops until you run
/tokenagain. A refresh never extends the window. Tokens that are still valid keep working after the 20 hours. - Keep a tab of the instance open. Without one there is nothing to refresh from, and a manual
/tokenis still needed. - An automatic refresh always targets one exact instance. A request that names no instance, or uses a wildcard address, is refused.
- To switch automatic refresh off for an instance, use the Automatic token refresh switch in the helper tab's Instances tab, or when you approve a new instance. With it off, only a manual
/tokensends a token. - Tokens are per hostname. If you reach one instance through two addresses, run
/tokenonce on the address your agent uses. /tokenworks from any page of the instance. When the page holds no session token of its own, SN Utils asks the instance for one. An empty token is never sent: if there is none,/tokentells you why.- If
/tokenreports that the instance does not issue session tokens, CSRF tokens appear to be switched off on that instance, so there is nothing to send. Ask your instance administrator about it. - One helper tab holds the connection at a time. If you work with several browser profiles, the helper tab you opened last is the active one. The others show Standing by and reconnect by themselves when that tab closes. Click Use this tab instead in a standby tab to switch.
- Not refreshing? Check the switch and the window in the Instances tab, then run
snu doctor. It reports the state of the bridge identity that this feature relies on and tells you how to reset it.
A program the helper tab has not seen before never receives a token on its own. It gets one only after you run /token yourself, and no token is ever stored by the helper tab.
Security
Comprehensive security measures protect your workspace and ServiceNow instance:
- Interactive Human Review — High-impact actions require explicit developer approval in the browser helper tab before execution
- Per-Instance Access Control — Granular permission switches per connected ServiceNow instance
- Local-only HTTP server — bound to
127.0.0.1(never exposed on the network), preferring fixed port 1977 with an ephemeral fallback - Per-session token — every
POST /apirequest must carry theX-Agent-Token: <token>header; the token is regenerated each session - Known bridges only, for a limited time: automatic token refresh goes only to a bridge you have sent a token to by hand, for one exact instance, and only within 20 hours of that manual
/token; the bridge id is kept in your home directory and only its hash is stored in the browser - Write history records every write the helper tab sends to an instance, with the tool that asked for it; see Write History
- Pause switch — one click in the SN Utils helper tab blocks all incoming agent commands (
E_PAUSED) while manual editor saves keep working - Workspace boundary enforcement — All file operations are restricted to the local workspace with strict path containment checks