Building and Managing Workflows
Learn how to build custom agents with triggers, actions, and conditional logic; use template variables; and test and publish agents.
Understanding Agents and Automation
Custom agents let you automate work that runs based on triggers (manual, scheduled, events, or inbound webhooks) and execute a sequence of steps. Agents can integrate with Slack, Teams, Okta, HRIS systems, MDM tools, ServiceNow, GitHub, Jira, and Harmony itself.
Understanding the Agent Builder
The Agent Builder is a visual editor where you design agents by adding nodes and connecting them. Open Agents from the sidebar, then create a new agent or open an existing one. The builder shows a canvas with a trigger node at the top and action/logic nodes below.
Understanding the Canvas
The canvas is a drag-and-drop area where steps are laid out. Nodes connect via edges (lines). Use the zoom controls (bottom-left) to zoom and pan. Right-click on the canvas or on nodes to open context menus. Use Shift+drag to select multiple nodes. The canvas snaps nodes to a grid. The canvas clips cleanly to rounded corners that match the surrounding content card, so the builder looks consistent throughout.
Navigating the Agents List
Open Agents at /agents to see all custom agents. Each card shows the agent name, description, enabled state, and toggle. Click an agent to edit it. Click Build custom agent to start a new one (when the Agent Builder feature is enabled).
Creating Your First Agent
Click Build custom agent on the Agents page.
You're taken to the builder with a default Manual trigger.
Click the + handle below the trigger (or drag from it) to add a step.
Choose an action (e.g., Slack, Okta, Harmony) and an operation.
Configure the step in the Properties panel.
Add more steps as needed.
Save and enable the agent.
Building Agents
Adding Steps
From the trigger: Click the + handle at the bottom of the trigger node, or drag from it. A step selector appears; pick a category (Slack, Okta, Harmony, etc.) and an operation.
From an existing step: Drag from the output handle of a step to create a connection. Drop on the canvas to add a new step, or drop on another step's input handle to connect.
Context menu: Right-click the canvas to add a step at that position.
Connecting Steps
Drag from a step's output handle (bottom) to another step's input handle (top) to connect them. Connections define execution order. You can insert a new step into an existing connection by dropping the new step onto the edge.
Understanding Node Types
Trigger
Starts the agent. One per agent. Types: Manual, Scheduled, Event, Webhook.
Action
Performs an operation (Slack message, Okta request, create ticket, etc.).
Logic
Condition (if/else), Sleep (wait), or For Each (iterate over a list). Branches, delays, or loops execution.
Understanding Agent Triggers
Using Manual Triggers
The default trigger. The agent runs only when executed manually (from the toolbar Run button). You can define agent inputs (e.g., employee ID, ticket ID) that users provide when running.
Using Scheduled Triggers
Runs the agent on a schedule. In the trigger configuration, select Scheduled and set:
Cron expression - Standard cron format (e.g.,
0 9 * * 1-5for 9:00 AM weekdays).Timezone - Timezone for the schedule (e.g., America/New_York).
Using Event Triggers
Runs when a specific event occurs. Select Event and choose an event type:
Ticket Created
When a new ticket is created.
Ticket Assigned
When a ticket is assigned to someone.
Ticket Status Changed
When a ticket's status changes.
Ticket Resolved
When a ticket is marked as resolved.
When you select an event trigger, the condition builder shows a dropdown of valid fields specific to that event type. Typing {{ trigger. in any step input surfaces an autocomplete list of available fields, so you always know exactly which fields are available without guessing.
Available fields by event type:
Ticket Created - ticket ID, title, priority, status, reporter, and desk
Ticket Status Changed - fields reflecting the previous and new status, plus ticket metadata
Using Webhook Triggers
Runs when an external system sends an HTTP request to a unique webhook URL generated for the agent. When you save an agent with a webhook trigger, the URL is created automatically and is ready to use immediately.
The full request body is passed into your agent as {{ trigger.* }} data, so every field sent by the external system is available in downstream steps.
Authentication options:
API key (header)
Include a pre-shared key in a request header.
HMAC signature
Validate request authenticity using a shared secret.
Bearer token
Standard Authorization header with a bearer token.
You can retrieve the webhook URL at any time using GET /workflows/{id}/webhook-url.
Configuring Trigger Conditions
For event triggers, you can add conditions to filter when the agent runs (e.g., only for certain desks, statuses, or types). Use the conditions section in the trigger configuration.
Using Agent Actions
Understanding Action Blocks
Action blocks are steps that call an external system or Harmony. Each block has a schema-driven configuration form with inputs. Many inputs support template variables to pass data from previous steps or the trigger. Integration identifiers are surfaced on blocks so you can precisely target the right connection, and the integration selector dropdown shows the friendly name you assigned to each integration rather than internal system identifiers.
Integration Actions
Slack
Send message, update message, add/remove reaction, get thread replies.
Microsoft Teams
Send message, update message, get thread replies.
Okta
Get user, list groups, add/remove user from group, reset password, provision access, terminate sessions, deactivate user, unlock user, retrieve recovery email, add/remove users from groups.
HiBob
Get/create/update employee, list departments/jobs/employees.
Workday
Get/create/update employee, list departments/jobs/employees.
BambooHR
Get/create/update employee, list departments/jobs/employees.
ServiceNow
Run Flow, Create Ticket (incident/request), Create Service Request, discover available flows.
GitHub
Search users, retrieve SAML identities, list org teams and repo collaborators, add/remove team members.
Jira / JSM
Look up issues, manage projects and service management requests.
HTTP Actions
Use the HTTP block to make HTTP requests to any API. Configure URL, method, headers, and body. Supports template variables in the request.
MDM Actions
Kandji
Get device, list devices, custom request.
Jamf
Get device, list devices, custom request.
Intune
Get device, list devices, custom request.
Identity Provider Actions
Okta
Get user, list groups, add/remove users from groups (accepts a list of employee IDs), unlock user, terminate sessions, retrieve recovery email, reset password, deactivate user.
Microsoft Entra
Get user, list groups, add/remove users from groups, reset password, terminate sessions, deactivate user, unlock user, retrieve recovery email.
Google Workspace
Get user, list groups, add/remove users from groups, terminate sessions, unlock user, retrieve recovery email, custom request.
JumpCloud
List groups, add/remove users from groups, reset password, deactivate user, unlock user, terminate sessions, custom request.
Active Directory (on-premises)
Unlock user accounts and additional identity management operations.
Group membership actions accept a list of employee IDs so you can add or remove multiple users in a single step. The action formerly called "Add to Groups" is now named Add Users to Groups.
AI Actions
Use the AI block to analyze content or generate responses. Useful for automated triage, summarization, or classification.
OTP Verification Actions
Use the OTP Verification blocks to add secure one-time password identity checks to your agents. The flow is handled end-to-end: a code is generated, delivered to the employee by email, and they are prompted to submit it via a Slack or Microsoft Teams form - all within the agent itself.
Sensitive values such as OTP codes and temporary passwords are encrypted at rest and are never exposed in plain text in run history, API responses, or step outputs.
Harmony Actions
Approval
Pause for human approval before continuing.
Create Ticket
Create a Harmony ticket.
Get/Update Ticket
Fetch or update a ticket.
List Tickets
List tickets with filters.
Get Employee
Fetch employee data by ID or email address.
List Employees
List employees, with filters for VIP status, employment status, location, and employment start date range (all applied server-side).
Get Devices
Fetch devices for an employee.
Update Device
Update device attributes.
Update Asset
Update asset attributes, including setting a manual sale price.
List/Get Application
Fetch application data.
Get Employee Applications
List apps for an employee.
Send Email
Send an email.
Resolve Approver
Resolve who should approve.
Resolve Identity Provider
Resolve IdP for an employee.
Generate CSV Report
Generate a CSV report.
Looking Up Employees
The Get Employee block supports two lookup methods - by employee ID or by email address. Both methods return the same employee data and work seamlessly with downstream steps.
Filtering Employee Lists
The List Employees block supports server-side filtering by:
VIP status
Employment status
Location
Employment start date range
Setting Asset Sale Prices
In the Update Asset block, add a Manual Sale Price value to save a price directly to the asset's purchase details. Only the price fields are updated - no other purchase details (such as ABM-sourced data) are overwritten.
Using Conditional Logic
Using Conditional Logic (If/Else)
Add a Condition block from the Logic category. Configure a condition; the agent branches to different paths based on whether the condition is true or false. Connect follow-up steps to the "true" or "false" output handles.
Setting Up Conditions
In the Condition block form, select a field (from trigger or prior steps), an operator (equals, contains, greater than, etc.), and a value. You can add multiple conditions and choose whether all or any must match.
Understanding Field Operators
Common operators: equals, not equals, contains, not contains, starts with, ends with, greater than, less than, is empty, is not empty. The available operators depend on the field type.
Building Complex Conditions
Combine multiple conditions with AND/OR. Use nested Condition blocks for complex branching.
Using Logic Blocks
Pausing an Agent with the Sleep Block
Add a Sleep block from the Logic category to pause the agent for a precise amount of time before continuing to the next step. The timer is fully durable - it survives server restarts and continues reliably even across multi-day waits without consuming processing resources.
Duration options:
Specify the wait in minutes, hours, or days - or combine all three for an additive total (e.g., 1 day + 2 hours + 30 minutes).
Use a template expression for dynamic durations (e.g.,
{{ config.jit_duration_minutes }}), so wait times can vary based on agent data.
Iterating Over Lists with the For Each Block
Add a For Each block to iterate over a list and execute a set of steps for each item. This is useful for bulk actions such as notifying a list of employees, processing multiple tickets, or enriching a set of records.
Key configuration options:
items
The list to iterate over, specified as a dynamic expression (e.g., {{ steps.list_employees.employees }}).
max_parallel
How many items are processed at the same time. Default: 5, maximum: 20.
continue_on_item_error
Whether a failure on one item stops the entire loop or allows remaining items to continue.
Working with Variables and Templates
Using Template Variables
Reference data from the trigger or previous steps using {{ ... }} syntax:
Agent inputs:
{{ input.employee_id }}(manual trigger inputs)Trigger event data:
{{ trigger.ticket_id }}(event triggers)Webhook data:
{{ trigger.* }}(any field from the webhook request body)Step outputs:
{{ steps.step_id.output_field }}(outputs from prior steps)
Understanding Available Variables
Variables depend on the current node's position. Only inputs and outputs from steps that run before the current node are available. The Template Picker and Token Input show available variables with autocomplete.
Inserting Variables in Actions
In action block fields that support templates, type {{ to open the template picker, or click the variable button. Select a variable to insert it into the field.
Using the Template Picker
The Template Picker modal shows a tree of available variables grouped by source (inputs, trigger, steps). Expand nodes to find the path, then insert it into your field.
Working with Token Inputs
Fields that support templates use a Token Input. It shows inserted variables as tokens. Click a token to edit or remove it. Type to search available variables.
Understanding Token Autocomplete
When typing {{ in a token input, autocomplete suggests variables. Variables are filtered by the current node's context (preceding steps and trigger). When typing {{ trigger. in any step input, autocomplete surfaces the specific fields available for the selected trigger event type.
Managing and Testing Agents
Editing Existing Agents
Open an agent from the Agents list. The builder loads the agent. Make changes to nodes, connections, or configuration. Save to persist. Unsaved changes are indicated in the toolbar.
Testing Agent Steps
Select an action node and click Test this step (or the play icon on the node). The Execute Step modal opens. Provide test values for required inputs and run the step in isolation - without running the full agent. Inputs are validated against the block's schema before execution, so you get a clear error immediately if something is misconfigured. View the output to verify the step works before running the full agent.
Re-executing Failed Steps
From a run's detail view, you can re-run a specific failed step using its original inputs or modified ones. This means you can fix a misconfiguration and retry just that step without replaying the entire agent.
Executing Agents
Click Run in the toolbar to execute the agent. For manual triggers, provide any required inputs in the dialog. The agent runs and the Runs drawer opens with the run result.
Viewing Agent Run History
Click the Runs (History) button in the toolbar to open the Runs drawer. It lists recent runs with status, duration, and timestamps. Click a run to expand and see step-by-step execution.
Understanding Agent Run Details
Each run shows: Run ID, status (running, completed, failed), duration, and step list. Expand a step to see its input, output, and any error. Completed steps show green; failed steps show red with the error message. Sensitive values such as OTP codes are never exposed in plain text in run history or step outputs.
Viewing Step Execution Results
In the Runs drawer, expand a run and a step to see Input (JSON sent to the step), Output (JSON returned), and Error (if the step failed).
Understanding Agent Errors
When a step fails, the error message appears in the step details. Common causes: invalid inputs, integration misconfiguration, API rate limits, or missing permissions. Use the error message and step input/output to troubleshoot.
Troubleshooting Failed Steps
Check the error message in the step details.
Verify inputs (templates resolve correctly, required fields are set).
Confirm the integration is connected and has the right scopes.
Use Test this step to test the step in isolation with sample data.
From the run detail view, re-run the failed step with corrected inputs.
Monitoring Agent Health
Harmony automatically monitors the health of your agents and detects when a dependency an agent relies on becomes unavailable. When a desk, sub-desk, or employee referenced by an agent is deleted or terminated, that agent is instantly marked as degraded with a reason and timestamp - so broken agents surface immediately rather than silently failing when triggered.
You can retrieve an agent's current health status at any time using GET /workflows/{id}/health. The response includes the status (healthy or degraded) and, when degraded, the reason and the time it was detected.
Getting Notified on Agent Failures
Each agent can be configured with its own failure notification target. When a step fails, Harmony sends an alert immediately to your chosen destination. Notifications include:
The agent name and the specific step that failed
The error message with full context
A direct link to the failed run so you can jump straight into debugging
Supported notification targets: Slack channels, Slack DMs, Microsoft Teams channels, and Teams direct messages. Configure the notification target in the agent Settings drawer.
Managing Agent Versions
You can add a human-readable description to each agent version to track what changed. When saving or updating a version, include a short note - for example, "Fixed approval timeout from 48h to 72h" or "Added JIT support."
Descriptions appear alongside the version number, timestamp, and author in the version history list.
You can set or update a description at any time after a version is created.
Descriptions are optional; versions without one still appear in the history list.
Duplicating Agents
Duplicate an existing agent via the API using POST /workflows/{id}/duplicate. The copy is a fully independent agent - editing the duplicate never affects the original.
The duplicate includes all steps, triggers, configuration schema, error handling, metadata (icon, tags), and branch logic. You can supply an optional name in the request body; if omitted, the copy is named "{original name} (copy)". The duplicate starts at version 1.0.0 and is created in a disabled state.
Bulk Deleting Agents
Delete multiple agents in a single API call using POST /workflows/bulk-delete. Pass an array of up to 50 agent IDs. All in-flight runs are cancelled and related signals, trigger subscriptions, and event waits are removed for each deleted agent.
If one or more agent IDs fail to delete, the response includes details of which deletions succeeded and which failed so you can handle partial failures gracefully.
Deleting Agents
Open the agent Settings drawer (gear icon) and scroll to the Danger zone. Click Delete Agent and confirm. The agent is permanently removed.
Using the Agent Toolbar and Properties
Using the Agent Toolbar
The toolbar at the top includes:
Back - Return to the Agents list.
Agent name - Click to edit. Click the emoji to change the agent icon.
Undo/Redo - Revert or reapply edits.
Run - Execute the agent.
Runs - Open the run history drawer.
Save - Save the agent.
Settings - Open agent settings (name, description, error notifications, delete).
Enabled - Toggle agent on/off (publish/unpublish).
AI - Open the AI agent builder.
Where to find in the UI
Open Agents in the sidebar, at
/agents.You will see both the prebuilt agents and any custom agents your team has built.
Select an agent to open it, at
/agents/{agentId}, or choose Build custom agent to start a new one.
Inside an agent, the toolbar carries Run, Save, Settings and the enable toggle, and the run history is in the top-right corner.
Last updated
Was this helpful?
