itential-mop skill
Build command templates with validation rules to run CLI checks and perform pre/post comparison analytics against network devices.
- GitHub stars
- 18
- Files
- 9
- Last commit
- Nov 5, 2026
- License
- GPL-3.0
- Allowed tools
- —
What does the itential-mop skill do?
itential-mop builds command templates with validation rules to run CLI checks and perform pre/post comparison analytics against network devices.
Summary generated from the skill's SKILL.md.
About the itential-mop skill
Network engineers and developers use this skill to automate read-only validation and compliance checks on network devices. It allows for the creation of command templates that execute specific CLI show commands and evaluate the resulting output against predefined validation rules. By using custom variable syntax, users can inject parameters into commands and rules to make them reusable across different hardware or interfaces.
Beyond simple command execution, the skill supports analytic templates to perform pre-change and post-change comparisons. This helps detect configuration drift by analyzing how command output evolves over time. The system supports various evaluation methods, including string containment, regular expressions, and numerical comparisons between two extracted values. It is strictly for read-only operations; users must use separate tools for pushing configuration changes to devices.
What an agent can do with it
- 1Automated pre-change validationRun a set of show commands to verify device state before applying new configurations.
- 2Detecting network configuration driftCompare command output from before and after a maintenance window to identify unexpected changes.
- 3Compliance auditing via CLIExecute standardized command templates across multiple devices to ensure they meet specific operational rules.
Written from the skill's SKILL.md. Every use case is checked against a quote from it.
How to install the itential-mop 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 itential-mop skill in Plugin
/plugin marketplace add itential/builder-skills /plugin install itential-builder@itential-builder
Install the itential-mop skill in Claude Code
~/.claude/skills/itential-mop/SKILL.md
$ npx degit itential/builder-skills/skills/itential-mop ~/.claude/skills/itential-mopInstall the itential-mop skill in Claude Code (project)
.claude/skills/itential-mop/SKILL.md
$ npx degit itential/builder-skills/skills/itential-mop .claude/skills/itential-mopInstall the itential-mop skill in Codex
~/.agents/skills/itential-mop/SKILL.md
$ npx degit itential/builder-skills/skills/itential-mop ~/.agents/skills/itential-mopInstall the itential-mop skill in Gemini CLI
~/.gemini/skills/itential-mop/SKILL.md
$ npx degit itential/builder-skills/skills/itential-mop ~/.gemini/skills/itential-mopInstall the itential-mop skill in Claude.ai
npx degit itential/builder-skills/skills/itential-mop itential-mop && zip -r itential-mop.zip itential-mop # claude.ai → Customize → Skills → + → Create skill → Upload a skill → itential-mop.zip
SKILL.md
View on GitHubMOP (Method of Procedure) - Developer Skills Guide
MOP manages command templates and analytic templates for running CLI commands against network devices with validation rules. Command templates execute show commands and evaluate the output against rules. Analytic templates compare command output before and after a change.
MOP is for read-only validation only -- never use it to push configuration to devices. Use Jinja2 templates and workflow tasks for config changes — see /itential-devices (Template Designer) or the environment's native config-push task (assets/AGENTS.md Rule 25).
Customization
Before using this skill, check custom/org/, custom/team/ and custom/dev/
in this skill's own folder. Read every .md file found — any folder may be
empty or absent. Apply them on top of everything below; where a file overrides a
specific rule here, follow the override. More specific wins: dev > team > org >
this document. No customization may weaken this skill's safety
rules or put credentials in committed files.
Bundled files: paths in this skill that start with assets/ or scripts/ are
relative to this skill's own folder. When you read one, or pass one to a shell
command (which runs from the user's working folder), use this skill's folder +
that relative path — e.g. <this skill's folder>/assets/helpers/create/create-workflow.json.
Concepts
- Command template = a set of CLI commands + validation rules, run against one or more devices
- Analytic template = pre/post comparison of command output to detect drift
- Variable syntax =
<!variable_name!>in both commands and rules (NOT{{ var }}or$var) - Pass/fail logic = hierarchical: template-level -> command-level -> rule-level, each with AND/OR control
API Reference
All /mop/* endpoints:
| Method | Endpoint | Description |
|---|---|---|
| POST | /mop/createTemplate |
Create a command template |
| GET | /mop/listTemplates |
List all command templates |
| GET | /mop/listATemplate/{name} |
Get a command template by name |
| POST | /mop/updateTemplate/{mopID} |
Update a command template (full replacement) |
| POST | /mop/deleteTemplate/{id} |
Delete a command template |
| POST | /mop/exportTemplate |
Export template (body: {"_id": "..."} or {"name": "..."}) |
| POST | /mop/importTemplate |
Import a template |
| POST | /mop/RunCommandTemplate |
Run a command template against devices |
| POST | /mop/RunCommand |
Run a single ad-hoc command on one device (workflow task) |
| POST | /mop/RunCommandDevices |
Run a single ad-hoc command on multiple devices |
| POST | /mop/RunCommandTemplateSingleCommand |
Run one command from a template by index |
| POST | /mop/GetBootFlash |
Get boot flash image name from a device |
| POST | /mop/reattempt |
Retry/delay mechanism for workflows |
| POST | /mop/createAnalyticTemplate |
Create an analytic template |
| GET | /mop/listAnalyticTemplates |
List all analytic templates |
| GET | /mop/listAnAnalyticTemplate/{name} |
Get an analytic template by name (path param) |
| POST | /mop/updateAnalyticTemplate/{id} |
Update an analytic template |
| POST | /mop/deleteAnalyticTemplate/{id} |
Delete an analytic template |
| POST | /mop/runAnalyticsTemplate |
Run an analytic template (workflow task) |
Template Structure
Create with POST /mop/createTemplate. The body uses a {"mop": {...}} wrapper.
{
"mop": {
"name": "Port_Turn_Up_Pre_Check",
"description": "Validates interface and VLAN before port turn-up",
"os": "",
"passRule": true,
"ignoreWarnings": false,
"commands": [
{
"command": "show interface <!interface!>",
"passRule": true,
"rules": [
{
"rule": "line protocol is",
"eval": "contains",
"severity": "error"
}
]
},
{
"command": "show vlan brief",
"passRule": true,
"rules": [
{
"rule": "<!vlan_id!>",
"eval": "contains",
"severity": "error",
}
]
}
]
}
}
Field reference:
name-- template name (required, must be unique)description-- human-readable descriptionos-- target OS filter (empty string = any OS)passRule(template-level) --true= ALL commands must pass (AND),false= ONE command must pass (OR)ignoreWarnings-- see ignoreWarnings section belowcommands[]-- array of commands to executecommand-- the CLI command string. Variables use<!variable_name!>syntaxpassRule(command-level) --true= ALL rules must pass (AND),false= ONE rule must pass (OR)rules[]-- validation rules applied to the command outputrule-- the string or pattern to match against. Can contain<!variables!>eval-- evaluation operator (case-sensitive, see Rule Evaluation below)severity--"error","warning", or"info"flags-- optional evaluation flags (see Flags below)
Only "name" is required -- template validation uses AJV with strict=false, so minimal templates are accepted.
passRule Logic
- Template-level
passRule: true= ALL commands must pass (AND logic) - Template-level
passRule: false= at least ONE command must pass (OR logic) - Command-level
passRule: true= ALL rules in this command must pass (AND logic) - Command-level
passRule: false= at least ONE rule must pass (OR logic)
ignoreWarnings
Template-level field, default false. When true: only rules with severity: "error" count as real failures. Rules with severity: "warning" or "info" that fail are treated as passing. When false (default): all severity levels count.
{
"mop": {
"name": "...",
"passRule": true,
"ignoreWarnings": true,
"commands": [...]
}
}
Rule Evaluation
The eval field determines how rule matching works. Eval types are case-sensitive.
| Eval | Purpose | Example Rule |
|---|---|---|
contains |
String exists in output | "line protocol is" |
!contains |
String does NOT exist in output | "ERROR" |
contains1 |
String exists exactly once | "Active" |
RegEx |
Regex matches output (capital R and E!) | "/\\d+\\.\\d+/" |
!RegEx |
Regex does NOT match | "/ERROR/" |
#comparison |
Extract + compare two values | See details below |
Flags
Optional flags object on each rule:
case: true= case-INSENSITIVE matching (confusing name --case: truedoes NOT mean case-sensitive)global: true= global search (RegEx only)multiline: true=^/$match start/end of lines, not just start/end of string (RegEx only)
case is available for all eval types. global and multiline are only meaningful for RegEx and !RegEx.
#comparison Details
Extract two values from command output using regex, then compare numerically.
{
"rule": "/Available: (\\d+)/",
"ruleB": "/Total: (\\d+)/",
"eval": "#comparison",
"evaluator": ">=",
"severity": "error"
}
rule/ruleB-- regex patterns (in/pattern/format) to extract values from the command outputevaluator-- comparison operator:=,!=,<,>,<=,>=,%%operator -- passes ifruleB/rule * 100 <= percentage. Set"percentage": 80to pass if ruleB is at most 80% of rule.
Example with percentage:
{
"rule": "/Total: (\\d+)/",
"ruleB": "/Used: (\\d+)/",
"eval": "#comparison",
"evaluator": "%",
"percentage": 80,
"severity": "error"
}
Variable Substitution
- Syntax:
<!variable_name!>in both commands and rules - Variables are substituted BEFORE execution
- If a variable is missing, the command is SKIPPED (not failed!) and counts as PASSED
- This syntax is different from Jinja2 templates (
{{ var }}) and workflow variable references ($var.job.x)
Example command with variables:
{
"command": "show running-config interface <!interface!>",
"passRule": true,
"rules": [
{
"rule": "switchport access vlan <!vlan_id!>",
"eval": "contains",
"severity": "error",
"evaluation": "pass"
}
]
}
Execution
Standalone (without a workflow)
POST /mop/RunCommandTemplate
{
"template": "Port_Turn_Up_Pre_Check",
"variables": {
"interface": "GigabitEthernet0/1",
"vlan_id": "100"
},
"devices": ["IOS-CAT8KV-1"]
}
template-- template name (string)variables-- object with values for<!variable!>substitutionsdevices-- array of device names (or single device name string)
In a Workflow
Use the MOP.RunCommandTemplate task. See /builder-agent for full workflow task wiring patterns.
{
"incoming": {
"template": "$var.job.templateName",
"variables": "$var.job.templateVariables",
"devices": "$var.job.devices"
},
"outgoing": {
"mop_template_results": null
}
}
template-- name of the command template (string or$varreference)variables-- object with values for<!variable!>substitutionsdevices-- array of device names to run against
See /builder-agent for running the workflow via POST /operations-manager/jobs/start.
Ad-Hoc Commands (without a template)
Run a single command directly without creating a template first:
POST /mop/RunCommand
{
"command": "show version",
"variables": {},
"device": "IOS-CAT8KV-1"
}
Returns: {raw, evaluated, device, response, result} — same shape as one entry in commands_results.
For multiple devices: POST /mop/RunCommandDevices with "devices": ["dev1", "dev2"] (array instead of singular device).
To run a single command from an existing template by index: POST /mop/RunCommandTemplateSingleCommand with {"templateId": "name", "commandIndex": 0, "variables": {}, "devices": ["dev1"]}.
Response Shape
{
"all_pass_flag": true,
"result": true,
"name": "Port_Turn_Up_Pre_Check",
"commands_results": [
{
"raw": "show interface <!interface!>",
"evaluated": "show interface GigabitEthernet0/1",
"all_pass_flag": true,
"device": "IOS-CAT8KV-1",
"response": "...command output...",
"result": true,
"parameters": {"interface": "GigabitEthernet0/1"},
"rules": [
{"rule": "line protocol is", "eval": "contains", "result": true, "severity": "error"}
]
}
]
}
result(top-level) -- overall template pass/fail (boolean)all_pass_flag(top-level) -- the template's passRule settingcommands_results[]-- one entry per command per deviceraw-- original command string (before variable substitution)evaluated-- command with variables substitutedresponse-- raw device outputresult-- whether this command passed (boolean)all_pass_flag-- this command's passRule settingdevice-- the device this command ran againstparameters-- the variables that were substitutedrules[].result--true/falsefor each individual rule
Update
POST /mop/updateTemplate/{mopID}
The mopID is the template name (URL-encoded). Uses the same {"mop": {...}} body wrapper as create. The body is a full replacement -- include ALL fields, not just changed ones.
Response on success:
{
"n": 1,
"ok": 1,
"nModified": 1
}
Analytic Templates
Analytic templates compare command output before and after a change to detect drift or validate results. Endpoints are listed in the API Reference table above.
Create an Analytic Template
POST /mop/createAnalyticTemplate
{
"name": "Interface_Change_Validation",
"os": "cisco-ios",
"passRule": true,
"prepostCommands": [
{
"preRawCommand": "show interface GigabitEthernet0/1",
"postRawCommand": "show interface GigabitEthernet0/1",
"passRule": true,
"rules": [
{
"type": "matches",
"preRegex": "/line protocol is (\\w+)/",
"postRegex": "/line protocol is (\\w+)/",
"evaluator": "="
}
]
}
]
}
Structure
name-- template nameos-- target OSpassRule--true= ALL prepostCommands must pass (AND),false= ONE must pass (OR)prepostCommands[]-- array of pre/post command pairspreRawCommand-- CLI command to run before the changepostRawCommand-- CLI command to run after the changepassRule--true= ALL rules must pass,false= ONE must passrules[]-- comparison rulestype--matches,!matches,regex, ortablepreRegex-- regex to extract value from pre-change outputpostRegex-- regex to extract value from post-change outputevaluator-- comparison operator:=,!=,<,>,<=,>=,%
Rule Types
| Type | Purpose |
|---|---|
matches |
Pre and post extracted values must match per evaluation operator |
!matches |
Pre and post extracted values must NOT match |
regex |
Regex-based extraction and comparison |
table |
Table-based comparison of structured output |
Running an Analytic Template
In a workflow, use the MOP.runAnalyticsTemplate task:
{
"incoming": {
"pre": "$var.preCheckTaskId.mop_template_results",
"post": "$var.postCheckTaskId.mop_template_results",
"analytic_template_name": "Interface_Change_Validation",
"variables": {}
},
"outgoing": {
"analytic_result": null
}
}
Critical: The pre and post inputs must be the full RunCommandTemplate output object (which contains a commands_results property). Do NOT pass just the commands_results array — pass the entire result object.
Gotcha: Pre and post commands must have exactly 1 match each in the collected results. If 0 or >1 match, it produces an error. The matching compares against both the raw and evaluated command strings — if variables were used, the evaluated string (with variables replaced) is what will match.
Gotchas
-
Missing variable = skip = PASS (not fail) -- if a
<!var!>token has no value, the command is silently skipped and counts as PASSED. Verify variables are passed correctly. -
case: true= case-INsensitive -- confusing naming."flags": {"case": true}enables case-insensitive matching. It does NOT mean case-sensitive. -
Empty rules = auto-pass -- a command with no rules (
"rules": []) always passes. Add at least one rule if you want validation. -
RegEx 5-second timeout -- complex regex patterns run in a sandboxed VM with a 5-second limit. Patterns prone to catastrophic backtracking will timeout.
-
containsdoes substring matching --"100"matches"1002". For exact matching, useRegExwith multiline flag:{"rule": "^<!vlanId!>\\s+", "eval": "RegEx", "severity": "error", "flags": {"multiline": true}} -
Eval types are case-sensitive --
"RegEx"not"regex"or"REGEX"."#comparison"not"Comparison". -
Only "name" is required -- template validation uses AJV with strict=false. Minimal templates are accepted.
-
Update is full replacement --
POST /mop/updateTemplate/{mopID}replaces the entire template. Include ALL fields when updating, not just changed ones. -
MOP is read-only -- command templates run show commands and evaluate output. Never use MOP to push configuration changes. Use Jinja2 templates and workflow adapter tasks for config changes.
-
_idequalsname-- the engine sets_id = nameon create. They are always identical. Use either for lookups. -
Rule-level missing variable ≠ command-level skip -- if a command has
<!var!>missing, the whole command is skipped (passes). But if a rule has<!var!>missing, it getseval: "missing_parameters"and returns"Invalid Rule: Missing Parameters"withresult: false. The rule fails, not skips. -
Template name change on update = delete + create -- if you update with a different name, the engine deletes the old template and creates a new one. This is destructive — the old
_idis gone. -
Import renames on collision --
importTemplatedoes not fail on duplicate names. It appends(N)to the name (e.g.,My_TemplatebecomesMy_Template (1)). -
Cannot set
namespacedirectly -- providingnamespacein the create body throws an error. Namespaces are managed through project membership.
Helper Templates
Always start from a helper template when creating assets. Read the helper file first, then modify it.
| File | API Call | Purpose |
|---|---|---|
assets/helpers/create/create-command-template.json |
POST /mop/createTemplate |
Command template with rules |
assets/helpers/update/update-command-template.json |
POST /mop/updateTemplate/{mopID} |
Update template (full replacement) |
Developer Scenarios
1. Build a pre-check command template
- Identify the show commands needed (e.g.,
show interface,show vlan brief) - Read
assets/helpers/create/create-command-template.jsonas a starting template - Fill in
name,description, add commands with<!variable!>placeholders - Add rules for each command -- use
containsfor simple checks,RegExfor pattern matching - Set
passRuleat template and command level (AND vs OR logic) - Create with
POST /mop/createTemplate - Test standalone with
POST /mop/RunCommandTemplateproviding variables and devices - Check
result(top-level) andcommands_results[].rules[].resultfor pass/fail details
2. Wire RunCommandTemplate into a workflow
After standalone testing passes:
- Use
/builder-agentto build a workflow - Add a
MOP.RunCommandTemplatetask to the workflow - Wire incoming variables:
template,variables,devicesusing$var.job.*references - Wire outgoing: capture results in a variable like
mop_template_results - Add downstream logic to branch on
$var.taskName.result(true/false) - Use
/builder-agentto run viaPOST /operations-manager/jobs/start
3. Build an analytic template for pre/post comparison
- Identify the commands to run before and after the change
- Create an analytic template with
POST /mop/createAnalyticTemplate - Define
prepostCommandswith pre/post command pairs - Add rules with
preRegex/postRegexto extract values for comparison - Set
evaluationoperator (=to verify values match,!=to verify they changed) - In a workflow: run pre-change commands, execute the change, run post-change commands, compare
- Remember: pre and post commands must have exactly 1 match each in results
Files in this skill
9itential-mop skill questions
How do I install the itential-mop skill in Claude Code?
Run npx degit itential/builder-skills/skills/itential-mop ~/.claude/skills/itential-mop. 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 itential-mop 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.
Can I use MOP to push configuration changes to network devices?
No, MOP is for read-only validation only. You should use Jinja2 templates and workflow tasks for configuration changes.
What happens if a variable is missing in a command template?
If a variable is missing, the command is skipped rather than failed, and it is counted as passed.