servicenow-change-workflow
$
npx mdskill add automateyournetwork/netclaw/servicenow-change-workflowManages end-to-end ITSM-gated network change workflows with audit trails
- Tracks change requests from creation to closure following ITIL processes
- Integrates with ServiceNow, pyats-config-mgmt, and GAIT for execution and auditing
- Enforces approval gates and validates incidents before and after changes
- Delivers status updates and audit trails through structured workflow states
SKILL.md
.github/skills/servicenow-change-workflowView on GitHub ↗
---
name: servicenow-change-workflow
description: "Full ITSM-gated change lifecycle - CR creation, pre-change incident validation, approval gate, execution via pyats-config-mgmt, post-change verification, and closure with GAIT audit trail. Use when creating a change request, making a network change that needs approval, tracking change management, or following ITIL change process."
license: Apache-2.0
user-invocable: true
metadata:
{ "openclaw": { "requires": { "bins": ["python3"], "env": ["SERVICENOW_MCP_SCRIPT"] } } }
---
# ServiceNow Change Workflow
## Golden Rule
**NEVER execute a network change without an approved Change Request.** The only exception is an Emergency change, which still requires a CR and immediate human notification.
## How to Call the Tools
The ServiceNow MCP server provides change management and incident tools. Call them via mcp-call:
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" TOOL_NAME '{"param":"value"}'
```
## ServiceNow Change Request States
```
New -> Assess -> Authorize -> Scheduled -> Implement -> Review -> Closed
\-> Canceled
```
- **New**: CR created, not yet submitted
- **Assess**: Submitted for review / risk assessment
- **Authorize**: Awaiting approval
- **Scheduled**: Approved and scheduled for implementation window
- **Implement**: Approved and ready for execution (this is the gate)
- **Review**: Post-implementation review
- **Closed**: Change completed and verified
## Change Types
| Type | Approval | Use When |
|------|----------|----------|
| Normal | CAB / manager approval required | Interface config, routing changes, ACL updates, any production change |
| Standard | Pre-approved template | Password rotation, NTP update, banner change |
| Emergency | Expedited (post-facto approval OK) | Active outage, security incident, critical vulnerability |
---
## Full Change Lifecycle
### Phase 0: Pre-Change Incident Check
Before creating a CR, verify no open P1/P2 incidents exist on affected CIs. Executing changes during active incidents violates ITIL best practice and risks compounding the outage.
#### 0A: Check for Open Critical Incidents
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" list_incidents '{"limit":20,"state":"1","query":"priority=1^ORpriority=2"}'
```
State `1` = New/Open. Review results for any incidents affecting the target device or service.
**Decision gate:**
- Open P1/P2 on affected CI -> STOP. Do not proceed. Notify the human.
- Open P1/P2 on unrelated CI -> Proceed with caution, note in CR description.
- No open P1/P2 -> Proceed.
#### 0B: Check for Active Change Freezes
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" list_change_requests '{"limit":10,"state":"implement","type":"normal"}'
```
Review active in-progress changes for conflicts. Two changes on the same device at the same time is a collision.
### Phase 1: Create Change Request
#### 1A: Create the CR
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" create_change_request '{"short_description":"Add Loopback99 to R1 for OSPF RID migration","description":"Add Loopback99 (99.99.99.99/32) to R1 as new OSPF router-id. Pre-change baseline captured. Rollback plan: no interface Loopback99. Affected CI: R1 (devnetsandboxiosxec8k.cisco.com). No open P1/P2 incidents on this CI.","type":"normal","category":"Network","risk":"moderate","impact":"3","assignment_group":"Network Engineering"}'
```
**CR description must include:**
1. What is being changed and why
2. Affected CI (device hostname, management IP)
3. Pre-change incident status (from Phase 0)
4. Rollback plan
5. Expected impact and duration
6. Verification criteria
#### 1B: Add Change Tasks
Break the change into discrete tasks for tracking:
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" add_change_task '{"change_id":"CHG0000123","short_description":"Capture pre-change baseline on R1","description":"Save running config, OSPF neighbors, routing table, interface states, and connectivity baselines."}'
```
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" add_change_task '{"change_id":"CHG0000123","short_description":"Apply Loopback99 configuration on R1","description":"Apply: interface Loopback99, ip address 99.99.99.99 255.255.255.255, description OSPF-RID-Migration, no shutdown"}'
```
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" add_change_task '{"change_id":"CHG0000123","short_description":"Post-change verification on R1","description":"Verify Loopback99 up/up, OSPF neighbors stable, routing table +1 connected route, connectivity 100%."}'
```
#### 1C: Record CR Creation in GAIT
```bash
python3 $MCP_CALL "python3 -u $GAIT_MCP_SCRIPT" gait_record_turn '{"user_text":"Create change request for Loopback99 addition on R1","assistant_text":"Created CR CHG0000123: Add Loopback99 to R1 for OSPF RID migration. Type: normal, Risk: moderate, Impact: 3. 3 change tasks added. Pre-change incident check: CLEAR (no P1/P2 on R1)."}'
```
### Phase 2: Approval Gate
#### 2A: Submit for Approval
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" submit_change_for_approval '{"change_id":"CHG0000123","approval_comments":"Pre-change checks complete. No open P1/P2 incidents. Rollback plan documented. Ready for CAB review."}'
```
#### 2B: Wait for Approval
Poll the CR status until it reaches Implement state:
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" get_change_request_details '{"change_id":"CHG0000123"}'
```
**Decision gate:**
- State = `implement` -> Proceed to Phase 3
- State = `authorize` -> Still awaiting approval. Wait.
- State = `canceled` -> CR was rejected. STOP. Notify the human with rejection reason.
**CRITICAL: Do NOT proceed to Phase 3 unless the CR state is `implement` (approved).**
#### 2C: Approve Change (when authorized to do so)
If the human operator has approval authority:
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" approve_change '{"change_id":"CHG0000123","approval_comments":"Approved. Rollback plan verified. Maintenance window confirmed."}'
```
### Phase 3: Execution
This phase uses the **pyats-config-mgmt** skill for the actual device work. The ServiceNow CR gates entry to this phase.
#### 3A: Update CR to Implementation
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" update_change_request '{"change_id":"CHG0000123","work_notes":"Beginning implementation. Capturing pre-change baseline."}'
```
#### 3B: Pre-Change Baseline (via pyats-config-mgmt)
Follow the pyats-config-mgmt skill Phase 1 procedure:
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_show_running_config '{"device_name":"R1"}'
```
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_run_show_command '{"device_name":"R1","command":"show ip ospf neighbor"}'
```
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_run_show_command '{"device_name":"R1","command":"show ip route"}'
```
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_ping_from_network_device '{"device_name":"R1","command":"ping 8.8.8.8 repeat 10"}'
```
Update the CR with baseline status:
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" update_change_request '{"change_id":"CHG0000123","work_notes":"Pre-change baseline captured: Running config saved, 2 OSPF neighbors FULL, 47 routes, 100% connectivity to 8.8.8.8 (23ms RTT)."}'
```
#### 3C: Apply Configuration (via pyats-config-mgmt)
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_configure_device '{"device_name":"R1","config_commands":["interface Loopback99","ip address 99.99.99.99 255.255.255.255","description OSPF-RID-Migration","no shutdown"]}'
```
Update the CR:
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" update_change_request '{"change_id":"CHG0000123","work_notes":"Configuration applied to R1. Proceeding to post-change verification."}'
```
### Phase 4: Post-Change Verification
#### 4A: Verify the Change (via pyats-config-mgmt)
Follow the pyats-config-mgmt skill Phase 4 procedure:
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_show_running_config '{"device_name":"R1"}'
```
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_run_show_command '{"device_name":"R1","command":"show ip ospf neighbor"}'
```
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_run_show_command '{"device_name":"R1","command":"show ip route"}'
```
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_ping_from_network_device '{"device_name":"R1","command":"ping 8.8.8.8 repeat 10"}'
```
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_show_logging '{"device_name":"R1"}'
```
#### 4B: Verification Decision
**Compare pre-change vs post-change state:**
| Check | Pre-Change | Post-Change | Expected Delta |
|-------|-----------|-------------|----------------|
| OSPF neighbors | 2 FULL | 2 FULL | No change |
| Route count | 47 | 48 | +1 connected (99.99.99.99/32) |
| Connectivity | 100% | 100% | No change |
| New errors in log | - | %LINEPROTO-5-UPDOWN Lo99 up | Expected |
**Decision gate:**
- All checks PASS -> Proceed to Phase 5 (Close)
- Any check FAILS -> Initiate Rollback (Phase 4C), do NOT close the CR
#### 4C: Rollback (If Verification Fails)
If post-change verification fails, roll back immediately:
```bash
PYATS_TESTBED_PATH=$PYATS_TESTBED_PATH python3 $MCP_CALL "python3 -u $PYATS_MCP_SCRIPT" pyats_configure_device '{"device_name":"R1","config_commands":["no interface Loopback99"]}'
```
Update the CR with rollback details:
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" update_change_request '{"change_id":"CHG0000123","work_notes":"ROLLBACK EXECUTED: Post-change verification failed. [Describe what failed]. Configuration rolled back. Device restored to baseline state. Verification of rollback: [results]."}'
```
Create an incident for the failed change:
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" create_incident '{"short_description":"Failed change CHG0000123 on R1 - rollback executed","description":"Change CHG0000123 (Add Loopback99 to R1) failed post-change verification. Rollback executed successfully. Device restored to pre-change state. Root cause investigation required.","urgency":"2","impact":"2","category":"Network"}'
```
**CRITICAL: If rollback fails, this becomes a P1 incident. Notify the human IMMEDIATELY.**
### Phase 5: Close the Change Request
#### 5A: Update CR with Final Status
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" update_change_request '{"change_id":"CHG0000123","work_notes":"Post-change verification PASSED. OSPF neighbors stable (2 FULL), route table +1 connected (99.99.99.99/32), connectivity 100%, no unexpected log entries. Change successful.","state":"review"}'
```
#### 5B: Close the CR
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" update_change_request '{"change_id":"CHG0000123","state":"closed","work_notes":"Change completed successfully. All verification checks passed. No rollback required."}'
```
#### 5C: Record Full Session in GAIT
```bash
python3 $MCP_CALL "python3 -u $GAIT_MCP_SCRIPT" gait_record_turn '{"user_text":"Execute change CHG0000123: Add Loopback99 to R1","assistant_text":"Change CHG0000123 completed successfully.\n\nTimeline:\n- Pre-check: No open P1/P2 incidents on R1\n- CR created and approved\n- Baseline: 2 OSPF neighbors FULL, 47 routes, 100% connectivity\n- Config applied: interface Loopback99, 99.99.99.99/32\n- Verification: PASSED (2 OSPF FULL, 48 routes, 100% connectivity)\n- CR closed: successful\n\nArtifacts: Pre/post running config diff, routing table diff, log entries."}'
```
#### 5D: Display GAIT Audit Trail
```bash
python3 $MCP_CALL "python3 -u $GAIT_MCP_SCRIPT" gait_show '{"commit":"HEAD"}'
```
---
## Emergency Change Process
Emergency changes bypass the normal approval gate but still require a CR and immediate human notification.
### When to Use Emergency Changes
- Active outage requiring immediate remediation
- Security incident requiring immediate mitigation (e.g., ACL to block attack)
- Critical vulnerability with active exploitation
### Emergency Workflow
#### E1: Create Emergency CR
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" create_change_request '{"short_description":"EMERGENCY: Block attack source 203.0.113.99 on R1","description":"EMERGENCY CHANGE: Active DDoS from 203.0.113.99 detected. Applying inbound ACL on GigabitEthernet1 to block source. Post-facto approval required.","type":"emergency","category":"Network","risk":"high","impact":"1","assignment_group":"Network Engineering"}'
```
#### E2: Notify Human Immediately
**CRITICAL: For emergency changes, you MUST notify the human operator before executing.** State:
- The emergency condition
- The proposed remediation
- The CR number
- Request verbal/written approval to proceed
#### E3: Execute Upon Human Approval
Follow Phase 3 (Execution) with accelerated timelines. Baseline capture is still mandatory.
#### E4: Post-Facto Approval
After execution, submit the emergency CR for post-facto approval:
```bash
python3 $MCP_CALL "python3 -u $SERVICENOW_MCP_SCRIPT" submit_change_for_approval '{"change_id":"CHG0000456","approval_comments":"EMERGENCY CHANGE - Post-facto approval requested. Change executed during active incident. Full audit trail in GAIT."}'
```
---
## Integration with Other Skills
| Skill | Integration Point |
|-------|------------------|
| **pyats-config-mgmt** | Phase 3 (Execution) and Phase 4 (Verification) - actual device configuration |
| **pyats-health-check** | Pre-change device health validation before entering Phase 3 |
| **netbox-reconcile** | Post-change: verify NetBox source of truth reflects the change (or ticket the delta) |
| **GAIT** | Every phase records to the audit trail - CR creation, approval, execution, verification, closure |
| **markmap-viz** | Generate change summary mind map for complex multi-device changes |
## Change Report Format
After every change, produce this summary:
```
Change Report - CHG0000123
Date: YYYY-MM-DD HH:MM UTC
Device: R1 (devnetsandboxiosxec8k.cisco.com)
Type: Normal | Risk: Moderate | Impact: 3
Pre-Check: No open P1/P2 incidents on R1
Approval: Approved by [approver] at HH:MM UTC
Pre-Change State:
- OSPF neighbors: 2 (FULL)
- Routes: 47
- Connectivity: 100% to 8.8.8.8 (23ms)
Config Applied:
interface Loopback99
ip address 99.99.99.99 255.255.255.255
description OSPF-RID-Migration
no shutdown
Post-Change State:
- OSPF neighbors: 2 (FULL) - no change
- Routes: 48 (+1 connected 99.99.99.99/32)
- Connectivity: 100% to 8.8.8.8 (23ms) - no change
- Log: %LINEPROTO-5-UPDOWN Lo99 up/up (expected)
Verification: PASSED
Rollback Required: No
CR Status: Closed (successful)
GAIT Commit: [commit hash]
```
More from automateyournetwork/netclaw
- aap-automationRed Hat Ansible Automation Platform — inventory management, job template execution, project SCM sync, ad-hoc commands, host management, Galaxy content discovery. Use when automating infrastructure with Ansible, running playbooks, managing inventories, or searching for Ansible collections and roles.
- aap-edaEvent-Driven Ansible (EDA) — activation lifecycle, rulebook management, decision environments, event stream monitoring. Use when managing event-driven automation triggers, enabling/disabling activations, or reviewing EDA rulebooks.
- aap-lintansible-lint playbook and role validation — syntax checking, best practice enforcement, project-wide analysis, rule filtering. Use when validating Ansible playbooks, checking code quality, or enforcing automation best practices before deployment.
- aci-change-deploySafe ACI policy change deployment - ServiceNow CR lifecycle, pre/post-change fault baselines, APIC policy application, automatic rollback on fault delta, and GAIT audit trail. Use when deploying ACI policy changes, creating tenants or EPGs, pushing config to APIC, or running a change window with rollback protection.
- aci-fabric-auditComprehensive Cisco ACI fabric health audit - node status, tenant/VRF/BD/EPG policy review, contract analysis, fault triage, and endpoint learning verification. Use when auditing ACI fabric health, checking for faults, reviewing tenant policies, or running pre/post-change baselines on APIC.
- arista-cvpArista CloudVision Portal (CVP) automation via REST API — device inventory, events, connectivity monitoring, tag management (4 tools). Use when managing Arista devices, checking CloudVision events, monitoring network connectivity probes, or tagging devices in CVP.
- aruba-cx-configView and manage Aruba CX switch configurations, perform ISSU upgrades, and firmware operations
- aruba-cx-interfacesMonitor Aruba CX switch interface status, LLDP neighbors, and optical transceiver health
- aruba-cx-switchingView and manage Aruba CX switch VLANs and MAC address tables for Layer 2 operations
- aruba-cx-systemDiscover Aruba CX switch system information, firmware versions, and VSF topology