AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Workflow Creation

skill-happy-technologies-llc-happy-platform-skills-workflow-creation · by Happy-Technologies-LLC

Programmatic workflow creation via API/MCP - build complete workflows without the UI editor

No reviews yet
0 installs
18 views
0.0% view→install

Install

$ agentstack add skill-happy-technologies-llc-happy-platform-skills-workflow-creation

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-happy-technologies-llc-happy-platform-skills-workflow-creation)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Workflow Creation? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Programmatic Workflow Creation

Overview

This skill enables you to create complete ServiceNow workflows entirely via API/MCP without using the visual Workflow Editor. This is essential for:

  • Automation pipelines - Create workflows as part of CI/CD deployments
  • Templated solutions - Generate standardized workflows from templates
  • Mass creation - Build multiple similar workflows programmatically
  • Version control - Store workflow definitions as code in Git
  • Environment migration - Recreate workflows across instances

Key Discovery: Activities store their logic in the input field as JavaScript code. This enables full programmatic workflow creation by:

  1. Creating the workflow structure (wfworkflow, wfworkflow_version)
  2. Creating activities with embedded scripts (wf_activity)
  3. Linking activities with transitions (wftransition, wfcondition)
  4. Publishing the workflow version

Prerequisites

  • Roles: admin or workflow_admin
  • Permissions: Write access to workflow tables (wf_*)
  • Knowledge: Basic understanding of workflow concepts
  • Environment: Development or test instance (never create workflows in production first)
  • Related Skills: admin/update-set-management - Capture workflows in update sets

Table Architecture

Understanding the workflow tables is critical for programmatic creation.

Core Tables

wf_workflow (base definition)
    |
    +-- wf_workflow_version (published versions)
            |
            +-- wf_activity (activities with scripts)
            |       |
            |       +-- wf_element_definition (activity types)
            |       +-- wf_stage (optional stages)
            |
            +-- wf_transition (connects activities)
            |       |
            |       +-- wf_condition (transition logic)
            |
            +-- wf_condition (workflow-level conditions)

Key Relationships

| Table | Purpose | Key Fields | |-------|---------|------------| | wf_workflow | Base workflow definition | name, table, description | | wf_workflow_version | Versioned workflow | workflow, table, start, published | | wf_activity | Individual activities | workflowversion, input, x, y | | wf_transition | Activity connections | from, to, condition | | wf_condition | Transition conditions | activity, condition, elseflag | | wf_element_definition | Activity type definitions | name, default_input |

Procedure

Step 1: Discover Activity Types

First, identify available activity types (wfelementdefinition).

Using MCP:

Tool: SN-Query-Table
Parameters:
  table_name: wf_element_definition
  query: active=true
  fields: sys_id,name,category,description
  limit: 50

Common Activity Types:

| sys_id | Name | Use Case | |--------|------|----------| | 0a6c97790a0a0b2756919eb960284334 | Notification | Send email/SMS | | 1ca8d7cf0a0a0b265e9a000c2c08248c | Set Values | Set field values | | 35433da80a0a029a0028c639a1e51eb4 | Approval - User | User approval | | 354e911f0a0a029a00e6a0e6ad74206f | Approval - Group | Group approval | | 283e8bb80a2581021d036a052ffc3433 | Approval Coordinator | Multi-approval container | | 38891b6f0a0a0b1e00efdfdd77602027 | Catalog Task | Create catalog task | | 3961a1da0a0a0b5c00ecd84822f70d85 | Timer | Wait/delay | | 396807940a0a0b5c00afd9f67d9fd7a2 | Log Message | Debug logging | | 5994b389c0a80011000e64de81b1864c | Subflow | Call another workflow | | 7c9a2ba9c0a801650021ada408de0ebd | Join | Wait for multiple paths | | 7a8ea386c0a80066179bc1f5186e1d2b | Rollback | Go back to earlier activity |

Note: Custom script activities can omit activity_definition entirely.

Step 2: Create Base Workflow

Create the workflow container record.

Using MCP (Preferred):

Tool: SN-Create-Workflow
Parameters:
  name: "P1 Incident Auto-Assignment"
  table: "incident"
  description: "Auto-assign P1 incidents to on-call engineer"
  condition: "priority=1^state=1"

Using SN-Create-Record:

Tool: SN-Create-Record
Parameters:
  table_name: wf_workflow
  data:
    name: "P1 Incident Auto-Assignment"
    description: "Auto-assign P1 incidents to on-call engineer"
    template: false
    access: "public"

Important: The name and table fields become read-only after creation. Choose carefully.

Save the sys_id: workflow_sys_id

Step 3: Create Workflow Version

Create a version that holds the actual workflow logic.

Using MCP:

Tool: SN-Create-Record
Parameters:
  table_name: wf_workflow_version
  data:
    name: "P1 Incident Auto-Assignment"
    workflow: [workflow_sys_id]
    table: "incident"
    condition: "priority=1^state=1"
    active: true
    published: false
    order: 100
    run_multiple: false
    after_business_rules: true

Key Fields:

| Field | Purpose | Notes | |-------|---------|-------| | table | Target table | REQUIRED - what records trigger this | | condition | Trigger condition | Encoded query format | | active | Is active | Set true for workflow to run | | published | Is published | Set false initially, publish after testing | | run_multiple | Allow concurrent instances | Usually false | | after_business_rules | When to run | Usually true |

Save the sys_id: version_sys_id

Step 4: Create Activities

Create each activity with its embedded script.

Activity 1: Start Activity

Using MCP (Preferred):

Tool: SN-Create-Activity
Parameters:
  workflow_version_id: [version_sys_id]
  name: "Check On-Call Engineer"
  x: 100
  y: 100
  script: |
    // Find on-call engineer
    var oncall = new GlideRecord('on_call_rotation');
    oncall.addQuery('active', true);
    oncall.addQuery('group', current.assignment_group);
    oncall.query();
    if (oncall.next()) {
      workflow.scratchpad.oncall_engineer = oncall.user.toString();
      gs.info('Found on-call: ' + oncall.user.name);
    } else {
      workflow.scratchpad.oncall_engineer = '';
      gs.warn('No on-call engineer found');
    }

Using SN-Create-Record:

Tool: SN-Create-Record
Parameters:
  table_name: wf_activity
  data:
    name: "Check On-Call Engineer"
    workflow_version: [version_sys_id]
    x: 100
    y: 100
    width: 150
    height: 80
    input: |
      // Script content here...

Save the sys_id: activity_start_id

Activity 2: Decision/Branch Activity

Tool: SN-Create-Activity
Parameters:
  workflow_version_id: [version_sys_id]
  name: "Assign to On-Call"
  x: 250
  y: 100
  script: |
    // Assign incident based on on-call lookup
    if (workflow.scratchpad.oncall_engineer) {
      current.assigned_to = workflow.scratchpad.oncall_engineer;
      current.state = 2;  // In Progress
      current.work_notes = 'Auto-assigned to on-call engineer by workflow';
      current.update();
      answer = 'assigned';
      gs.info('Assigned to: ' + current.assigned_to.name);
    } else {
      answer = 'no_oncall';
      gs.warn('Could not assign - no on-call engineer');
    }

Save the sys_id: activity_assign_id

Activity 3: Notification Activity

Tool: SN-Create-Activity
Parameters:
  workflow_version_id: [version_sys_id]
  name: "Send Notification"
  x: 400
  y: 100
  type: "notification"
  script: |
    // Send email notification
    var email = new GlideEmailOutbound();
    email.setSubject('P1 Incident Assigned: ' + current.number);
    email.setFrom('noreply@company.com');
    email.addAddress(current.assigned_to.email);
    email.setBody('You have been assigned P1 incident: ' + current.number + '\n' +
                  'Priority: 1\n' +
                  'Short Description: ' + current.short_description);
    email.send();
    gs.info('Notification sent to: ' + current.assigned_to.email);

Save the sys_id: activity_notify_id

Activity 4: Escalation Activity (Branch Path)

Tool: SN-Create-Activity
Parameters:
  workflow_version_id: [version_sys_id]
  name: "Escalate to Manager"
  x: 250
  y: 250
  script: |
    // Escalate to manager
    var manager = current.assignment_group.manager;
    if (manager) {
      current.assigned_to = manager;
      current.escalation = 1;
      current.work_notes = 'Escalated to manager - no on-call engineer available';
      current.update();
      gs.info('Escalated to manager: ' + manager.name);
    }

Save the sys_id: activity_escalate_id

Step 5: Create Transition Conditions

Define conditions for branching paths.

Condition 1: "Assigned" Path

Tool: SN-Create-Record
Parameters:
  table_name: wf_condition
  data:
    activity: [activity_assign_id]
    name: "Assigned Successfully"
    short_description: "On-call engineer found and assigned"
    condition: "answer=assigned"
    order: 1

Save the sys_id: condition_assigned_id

Condition 2: "No On-Call" Path

Tool: SN-Create-Record
Parameters:
  table_name: wf_condition
  data:
    activity: [activity_assign_id]
    name: "No On-Call"
    short_description: "No on-call engineer found"
    condition: "answer=no_oncall"
    order: 2

Save the sys_id: condition_no_oncall_id

Else Condition (Default Path):

Tool: SN-Create-Record
Parameters:
  table_name: wf_condition
  data:
    activity: [activity_assign_id]
    name: "Default"
    short_description: "Default path"
    else_flag: true
    order: 99

Step 6: Create Transitions

Link activities together with transitions.

Using MCP (Preferred):

Tool: SN-Create-Transition
Parameters:
  from_activity_id: [activity_start_id]
  to_activity_id: [activity_assign_id]

Transition 1: Start to Assign

Tool: SN-Create-Record
Parameters:
  table_name: wf_transition
  data:
    from: [activity_start_id]
    to: [activity_assign_id]
    order: 1

Transition 2: Assign to Notify (Conditional)

Tool: SN-Create-Record
Parameters:
  table_name: wf_transition
  data:
    from: [activity_assign_id]
    to: [activity_notify_id]
    condition: [condition_assigned_id]
    order: 1

Transition 3: Assign to Escalate (Conditional)

Tool: SN-Create-Record
Parameters:
  table_name: wf_transition
  data:
    from: [activity_assign_id]
    to: [activity_escalate_id]
    condition: [condition_no_oncall_id]
    order: 2

Transition 4: Escalate to Notify (After Escalation)

Tool: SN-Create-Record
Parameters:
  table_name: wf_transition
  data:
    from: [activity_escalate_id]
    to: [activity_notify_id]
    order: 1

Step 7: Set Start Activity and Publish

Update the workflow version with the start activity and publish.

Using MCP (Preferred):

Tool: SN-Publish-Workflow
Parameters:
  workflow_version_id: [version_sys_id]
  start_activity_id: [activity_start_id]

Using SN-Update-Record:

Tool: SN-Update-Record
Parameters:
  table_name: wf_workflow_version
  sys_id: [version_sys_id]
  data:
    start: [activity_start_id]
    published: true

Step 8: Verify the Workflow

Query to verify workflow structure.

Check Activities:

Tool: SN-Query-Table
Parameters:
  table_name: wf_activity
  query: workflow_version=[version_sys_id]
  fields: sys_id,name,x,y

Check Transitions:

Tool: SN-Query-Table
Parameters:
  table_name: wf_transition
  query: from.workflow_version=[version_sys_id]
  fields: sys_id,from.name,to.name,condition.name

Check Workflow Version:

Tool: SN-Query-Table
Parameters:
  table_name: wf_workflow_version
  query: sys_id=[version_sys_id]
  fields: name,table,start.name,published,active

Workflow Context and Scripting

Available Variables in Activity Scripts

// The current record being processed
current

// Workflow scratchpad - share data between activities
workflow.scratchpad.your_variable = 'value';

// Activity result - determines which transition to follow
answer = 'approved';  // String that matches condition

// Current activity object
activity

// Workflow context
workflow.name
workflow.context.sys_id

Common Script Patterns

Pass Data Between Activities:

// Activity 1: Store data
workflow.scratchpad.user_tier = current.u_tier;
workflow.scratchpad.requires_approval = true;
workflow.scratchpad.approval_reasons = [];

// Activity 2: Use stored data
if (workflow.scratchpad.requires_approval) {
  var reasons = workflow.scratchpad.approval_reasons;
  // Process reasons...
}

Branch Logic with Answer Variable:

// Set answer to determine which transition fires
if (current.priority == 1) {
  answer = 'high_priority';
} else if (current.priority == 2) {
  answer = 'medium_priority';
} else {
  answer = 'low_priority';
}
// Create transitions with conditions: answer=high_priority, etc.

Error Handling:

try {
  var gr = new GlideRecord('incident');
  gr.get(current.sys_id);
  // Processing...
  answer = 'success';
} catch(e) {
  gs.error('Workflow error in ' + activity.name + ': ' + e.message);
  workflow.scratchpad.error_message = e.message;
  answer = 'error';
}

Logging for Debugging:

gs.info('[Workflow: ' + workflow.name + '] Activity: ' + activity.name);
gs.info('[Workflow] Processing incident: ' + current.number);
gs.info('[Workflow] Scratchpad data: ' + JSON.stringify(workflow.scratchpad));

Activity Type Examples

Approval - User

Tool: SN-Create-Activity
Parameters:
  workflow_version_id: [version_sys_id]
  name: "Manager Approval"
  x: 300
  y: 150
  type: "35433da80a0a029a0028c639a1e51eb4"
  script: |
    // Create approval request for manager
    var approval = new GlideRecord('sysapproval_approver');
    approval.initialize();
    approval.document_id = current.sys_id;
    approval.source_table = current.getTableName();
    approval.approver = current.opened_by.manager;
    approval.state = 'requested';
    approval.insert();
    gs.info('Approval created for: ' + current.opened_by.manager.name);

Approval - Group

Tool: SN-Create-Activity
Parameters:
  workflow_version_id: [version_sys_id]
  name: "CAB Approval"
  x: 300
  y: 150
  type: "354e911f0a0a029a00e6a0e6ad74206f"
  script: |
    // Create group approval request
    var approval = new GlideRecord('sysapproval_group');
    approval.initialize();
    approval.document_id = current.sys_id;
    approval.source_table = current.getTableName();
    approval.assignment_group = 'CAB';  // sys_id or name
    approval.state = 'requested';
    approval.insert();

Catalog Task

Tool: SN-Create-Activity
Parameters:
  workflow_version_id: [version_sys_id]
  name: "Create Fulfillment Task"
  x: 350
  y: 150
  type: "38891b6f0a0a0b1e00efdfdd77602027"
  script: |
    // Create catalog task
    var task = new GlideRecord('sc_task');
    task.initialize();
    task.request_item = current.sys_id;
    task.short_description = 'Fulfill: ' + current.short_description;
    task.assignment_group = current.assignment_group;
    task.state = 1;  // Open
    var taskId = task.insert();
    workflow.scratchpad.task_sys_id = taskId;
    gs.info('Created task: ' + task.number);

Timer/Wait

Tool: SN-Create-Activity
Parameters:
  workflow_version_id: [version_sys_id]
  name: "Wait 24 Hours"
  x: 400
  y: 150
  type: "3961a1da0a0a0b5c00ecd84822f70d85"
  script: |
    // Timer configuration is typically in vars field
    // This activity waits before proceeding
    gs.info('Timer started - will continue in 24 hours');

Notification

Tool: SN-Create-Activity
Parameters:
  workflow_version_id: [version_sys_id]
  name: "Send Email"
  x: 450
  y: 150
  type: "0a6c97790a0a0b2756919eb960284334"
  script: |
    // Send notification
    var email = new GlideEmailOutbound();
    email.setSubject('Request Update: ' + current.number);
    email.setFrom('noreply@company.com');
    email.addAddress(current.opened_by.email);
    email.setBody('Your request ' + current.number + ' has been processed.\n\n' +
                  'Status: ' + current.state.ge

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Happy-Technologies-LLC](https://github.com/Happy-Technologies-LLC)
- **Source:** [Happy-Technologies-LLC/happy-platform-skills](https://github.com/Happy-Technologies-LLC/happy-platform-skills)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.