Creating Workflows with the CLI (Early Access)

This feature is in the Early Access stage and under active development. Configuration schemas and behavior are subject to change. We recommend that you do not use this feature in production environments.

To build a workflow from the Solace Agent Mesh UI, and to understand what a workflow is and how it runs, see Creating Workflows (Early Access). This page covers authoring a workflow as version-controllable YAML, called declarative config: the YAML specific to the workflow kind. For the sam config plan, apply, and pull workflow that applies to every kind, see Managing Configuration as Code (Early Access).

Before You Start

You need a running Agent Mesh instance to apply your configuration to. For how to install or deploy one, see Install and Deploy.

Each agent node in a workflow delegates to an agent by name, so the agents a workflow references must already exist in your deployment. Build them first, either from the Agent Mesh UI or as declarative config, as described in Creating Agents. The following example references two agents named paragraph-writer and summarizer.

Write the Workflow

A workflow is one file under the workflows/ directory of a declarative-config repo, listed by name in the manifest:

# manifest.yaml
kind: manifest
name: topic-summary
description: Topic-summary workflow.
target:
  url: http://127.0.0.1:8800
resources:
  workflows:
    - topic-summary

The following file defines a two-step sequential workflow under spec.appConfig. The nodes are a list; each has an id, a type, and the fields for that type. The summarize node declares depends_on: [write_paragraph], so Agent Mesh runs it only after the first node completes. Each node's input and the workflow's output_mapping reference data with {{...}} templates: {{workflow.input.<field>}} reads a workflow input, and {{<node-id>.output}} reads a completed node's output.

# workflows/topic-summary.yaml
kind: workflow
name: topic-summary
description: Writes a paragraph about a topic and then condenses it into a single sentence.
spec:
  appConfig:
    description: Two-step sequential workflow.
    output_mapping:
      summary: "{{summarize.output}}"
    nodes:
      - id: write_paragraph
        type: agent
        agent_name: paragraph-writer
        input:
          message: "Write a short factual paragraph about {{workflow.input.topic}}."
      - id: summarize
        type: agent
        agent_name: summarizer
        depends_on:
          - write_paragraph
        input:
          message: "Condense this into one sentence: {{write_paragraph.output}}"

The top-level name and description identify the workflow; name is 3 to 255 characters and description is 10 to 2,000. The spec.appConfig fields are:

Field Description
description A description of the workflow, stored with its definition.
nodes The list of nodes in the graph. Each entry sets id, type, and the fields for that type.
output_mapping Required. Maps the workflow's outputs to node outputs, using {{<node-id>.output}} templates.

Every node shares three fields, plus fields specific to its type:

Field Description
id The node's unique identifier within the workflow.
type The node kind: agent, switch, map, loop, tool, nested workflow, or decision (Early Access).
depends_on The node IDs this node waits for. Agent Mesh runs a node after all of its dependencies have completed, which is how you order and branch the graph.

An agent node adds agent_name (the agent it delegates to) and an input mapping. A node's input references workflow inputs with {{workflow.input.<field>}} and upstream node outputs with {{<node-id>.output}}. The other node types take their own fields: switch (cases, default), map (node, items), loop (node, condition, max_iterations), tool (tool_name), nested workflow (workflow_name, input), and decision (questions, route_on, routes). A workflow with decision nodes also sets a decision block that names a decision model. For how to write a decision node, see Routing with Decision Nodes (Early Access).

To see every field a node type accepts, run sam config schema show workflow --type <node-type>, for example sam config schema show workflow --type switch.

Call Tools Directly with Tool Nodes

A tool node calls a tool without involving an agent or an LLM. The tools a workflow can call come from three places — two spec.appConfig fields declared alongside nodes, plus connector references on the nodes themselves:

Source Description
tools A raw tool list in the same shape agents accept, for example tool_type: builtin entries.
toolsets A list of toolset names, the same names agents accept in spec.toolsets: your own toolsets by name, or built-in toolset IDs such as builtin_artifact_tools.
connector: on a tool node A connector name in place of tool_name. When the connector produces more than one tool, add tool: to select one by its base name.

At deploy time, Agent Mesh expands each toolset into its tools. A toolset's tools register under <toolset>__<tool>, which is the name a tool node references in tool_name:

# workflows/greeter.yaml
kind: workflow
name: greeter
description: Calls a toolset tool directly, without an agent.
spec:
  appConfig:
    toolsets:
      - echo-tools
    output_mapping:
      greeting: "{{greet.output}}"
    nodes:
      - id: greet
        type: tool
        tool_name: echo-tools__greet
        input:
          name: "{{workflow.input.name}}"

Toolset-level configuration, such as API keys declared in the toolset's spec.config, is applied when the tools are expanded, so a workflow shares the same toolset configuration as the agents that use it. When you re-upload or reconfigure a toolset, Agent Mesh automatically redeploys the workflows bound to it, just as it redeploys agents.

A connector-backed node looks like this — the same connectors agents use, referenced by name (see Configuring Connectors):

    nodes:
      - id: fetch_pet
        type: tool
        connector: pets-api
        tool: getPetById
        input:
          pet_id: "{{workflow.input.petId}}"

Agent Mesh validates the connector name when you save the workflow and resolves it to the concrete tool at deploy time. When you edit or rename a connector, Agent Mesh automatically redeploys the workflows that reference it, and the reference survives the rename.

Write each input: key as the operation's parameter name in snake_case. For example, the petId parameter in the OpenAPI specification becomes pet_id. Agent Mesh adds a param_ prefix to a parameter named after a Python keyword, so from becomes param_from. Request body properties count as parameters.

When an OpenAPI connector has an uploaded specification, Agent Mesh checks the input: keys against the operation's parameters when you save and deploy the workflow. Agent Mesh rejects a node that leaves out a required parameter, except where the node's failure cannot stop a run (see the list later in this section). If a node includes a key that the operation does not declare, Agent Mesh does not reject the node. It logs a warning, the Builder shows the same warning, and the call is made without that key.

Agent Mesh also rejects a node that calls an operation the connector's allow_list names but the uploaded specification does not contain, with the same exceptions. Such a node fails every time it runs. The error names the allow_list entry and lists the operations that the specification declares. The Builder reports the same error when it validates the workflow.

Agent Mesh also rejects a tool node whose tool_name names a tool that none of the workflow's tool sources registers. Agent Mesh makes this check only when every tool source lists its tools in advance. This check has the same exceptions.

When you save or deploy a workflow, Agent Mesh rejects a tool node for a tool_name, required-parameter, or allow_list problem only if the node's failure can stop a run. The failure of a tool node cannot stop a run in these cases:

  • The node is an on_exit handler that no loop or map also runs. A failing on_exit handler does not change how the run ends.

  • The node's when: is the literal false, so it never runs.

  • The node never runs because each node it waits for either never runs or is a switch that never selects it. A switch never selects a node when every case that names the node has a condition that is the literal false or comes after a case whose condition is the literal true. If the node is also the default of the switch, the switch must also have a case whose condition is the literal true, because the switch then never uses its default.

  • The node is the template of a map whose items is a literal empty list, so the template never runs.

  • The node is the body of a loop, or the template of a map, and that loop or map never runs for one of the reasons above.

The when: condition, the dependencies, and the switch cases of a node count only if the workflow runs that node directly. The workflow's on_exit setting runs an on_exit handler, a loop runs its body, and a map runs its template. For those nodes, a when: condition or a switch does not decide whether the failure can stop a run.

In these cases, Agent Mesh saves and deploys the workflow and warns about the problem instead. The warning states the reason. Each place reports the warning as follows:

  • sam config plan prints the warning only for a tool_name problem. It does not run the required-parameter check or the allow_list check, because it cannot read a connector's specification.

  • The Builder shows the warning for all three checks.

  • The platform writes the warning to its log when you save or deploy the workflow.

In every other case, Agent Mesh rejects the failing node, because a run can reach it. This includes a workflow that sets fail_fast: false. With that setting, Agent Mesh skips every node that waits for the failing node, so a run that reaches the failing node still finishes as a success without doing that work. It also includes a node behind a when: or switch condition that reads data, the template of a map whose items reads data, and the body of a loop that can run. When Agent Mesh rejects a redeploy of a workflow that is already deployed, the previous instance keeps serving and the deployment record shows the error.

If a connector has only a specification URL, you must also set allow_list before a workflow node can use it. Agent Mesh does not check the input: keys for that connector.

A remote Model Context Protocol (MCP) connector works the same way. Set tool: to the tool's name on the MCP server. The field is required unless the connector's own tool selection leaves exactly one tool:

    nodes:
      - id: find_customer
        type: tool
        connector: acme-crm
        tool: find_customer
        input:
          company: "{{workflow.input.company}}"

Agent Mesh validates tool against the tool list stored with the connector. The stored list is the one Agent Mesh discovered when you saved the connector against a reachable server, narrowed by the connector's tool selection. If tool names a tool outside that list, Agent Mesh rejects the workflow when you save it, and the error names the tools the connector does offer. Agent Mesh also rejects the workflow if the connector has no stored tool list, unless the connector is pinned to one tool with tool_name. An OAuth connector needs a manifest instead of the pin. To correct the problem, save the connector again while its MCP server is reachable. If the connector uses OAuth, or holds its server address or credentials as ${...} references, Agent Mesh cannot discover its tools, so add a manifest value to the connector that lists its tools, each with a name and optionally a description and an inputSchema. A connector cannot hold both a manifest and any of tool_name, allow_list, or deny_list, so remove those fields before you add the manifest. If the connector's tool selection excludes all of its stored tools, change the selection. For more information about the tool-selection fields, see MCP Connectors via the CLI.

If a node calls an MCP tool and another MCP connector in the same workflow serves a tool that registers under the same name, Agent Mesh rejects the workflow when you save it, and the error names both connectors. Set tool_name_prefix on one of them to tell them apart. Agent Mesh does not compare the name with tools you declare in tools, tools from a toolset, or tools from API, SQL, and other connectors, so it does not report a clash with one of those tools. If one of them has the same name, set tool_name_prefix on the MCP connector.

A connector-backed MCP tool cannot carry tool_config, so a node cannot return only selected fields of a large response with extract_fields. To use extract_fields with an MCP server, declare the server in tools with tool_type: mcp instead.

Apply and Verify

Preview the change with sam config plan -m manifest.yaml, then apply the manifest to create and deploy the workflow:

sam config apply -m manifest.yaml
Applied workflows:
  + topic-summary  created
Deployments:
  * topic-summary  deploy (deploy) completed

To confirm the running state, open the Workflows page in the Agent Mesh UI, where topic-summary appears, or export it back into YAML with sam config pull -o ./pulled --url http://127.0.0.1:8800 --only workflow. For how the plan and apply diff works, including the display-only delete entries and --prune, see Managing Configuration as Code (Early Access).

What Next?

You have a workflow defined as version-controllable YAML and deployed with sam config apply. To confirm it's running and see it as a graph diagram, see Viewing and Managing Workflows. To classify and route on a decision model's answer, see Routing with Decision Nodes (Early Access).