Skip to content

Flows

A Flow is a YAML orchestration graph for a digital worker. It says where a message, event, timer, webhook, or pub/sub payload enters, which component-backed steps run, and where the result goes next.

Flows are stored in .ygtc files. In day-to-day work you usually do not hand-author every node. The practical workflow is:

  1. Use gtc wizard to create a bundle with providers, tenants, apps, and starter flows.
  2. Use greentic-flow wizard or greentic-flow add-step to add and update component-backed steps.
  3. Use a coding agent to fetch the wizard schemas, fill the answer files, and run the CLI non-interactively.
  4. Use greentic-flow doctor to validate the final flow and keep component resolve sidecars in sync.

Modern Greentic flows use the YGTc v2 shape: nodes is a map, every node has one operation key, and routing declares where execution continues.

flows/main.ygtc
id: main
title: Research Assistant
description: Answer research questions from a chat message.
type: messaging
start: answer_question
nodes:
answer_question:
component.exec:
component: deep-research-analyst
operation: answer
question: "{{in.input.text}}"
source_provider: webchat
routing:
- to: send_answer
send_answer:
emit.response:
messages:
- type: text
text: "{{prev.answer}}"
routing:
- out: true

The important fields are:

FieldPurpose
idStable flow identifier.
title / descriptionHuman-readable summary for operators and tooling.
typeFlow kind: messaging, webhook, timer, websocket, or pubsub.
startFirst node for the default entrypoint.
entrypointsOptional named entrypoints when one flow needs multiple starts.
nodesNamed steps. Each step has one operation key plus optional routing, telemetry, retry, timeout, and metadata.

A node is a single unit of work. The operation key determines what runs:

nodes:
present_telco:
component.exec:
component: component-telco-present
operation: present
query: "{{in.input.text}}"
metadata: "{{in.input.metadata}}"
message: "{{in.input}}"
source_provider: webchat
routing:
- to: respond_telco

Common operation families include:

OperationPurpose
component.execCall a WASM component operation.
emit.responseReturn one or more messages to the originating provider.
templateRender a wizard/config fragment, often inside component dev flows.
questionsAsk setup/config questions in component config flows.
qa.process, mcp.exec, templating.handlebarsComponent or adapter operations used by specific packs.

Component-backed nodes normally come from component manifests and their dev_flows. For example, component-templates exposes a text operation and a config flow that can ask for the Handlebars text, output path, wrapping mode, and routing target. The CLI can use that contract to generate a valid node instead of making you remember the exact YAML shape.

Routing is explicit and lives on each node:

routing:
- to: send_response

Terminal routes finish the flow:

routing:
- out: true

The schema accepts explicit route arrays such as { to: next_node }, terminal output routes such as { out: true }, and reply routes such as { reply: true }. Prefer the forms produced by the wizard and demo bundles unless you are editing a flow by hand for a specific reason.

Conditional routing can be represented with route conditions:

routing:
- to: approve_request
condition: "prev.confidence >= 0.8"
- to: escalate_request
condition: "prev.confidence < 0.8"

Flows use template expressions to pass data between nodes:

ExpressionMeaning
{{in}}Current flow input envelope.
{{in.input}}Provider-specific inbound message or event payload.
{{in.input.text}}Common chat message text field.
{{prev}}Output from the previous node.
{{prev.messages}}Example output passed directly into emit.response.

The Telco-X demo uses this pattern:

respond_telco:
emit.response:
messages: "{{prev.messages}}"
routing:
- out: true

That keeps the presentation component responsible for producing provider-ready messages, while the flow only routes the output.

Messaging flows usually start from chat extensions such as WebChat, Teams, Slack, Telegram, WhatsApp, Webex, or email. The deep research demo starts with an Adaptive Card menu, then routes either to a single research analyst or through a planner-and-analyst sequence:

flows/main.ygtc
id: main
title: Deep Research Demo
description: Adaptive-card deep research flow with single-shot and agentic research modes
type: messaging
start: main_menu
nodes:
main_menu:
component-adaptive-card.render:
card_source: asset
card_spec:
asset_path: assets/cards/main_menu.json
routing:
- status: agentic
to: research_planner
- status: single_shot
to: research_analyst
- out: true
research_planner:
component.exec:
component: component-llm-openai
operation: handle_message
input:
messages:
- role: system
content: "Turn the research goal into a focused plan."
- role: user
content: "{{entry.input.metadata.user_question}}"
routing:
- to: research_analyst
research_analyst:
component.exec:
component: component-llm-openai
operation: handle_message
input:
messages:
- role: system
content: "Produce a concise final research report."
- role: user
content: "{{entry.input.metadata.user_question}}"
routing:
- to: show_final_report
show_final_report:
component-adaptive-card.render:
card_source: asset
card_spec:
asset_path: assets/cards/final_report.json
routing:
- out: true

Event flows use the same graph model, but the entry payload comes from an event extension instead of a chat extension. Use webhook, timer, or pubsub as the flow type depending on the ingress.

There are two wizard layers:

ToolUse it for
gtc wizardCreating the bundle: providers, tenants, apps, starter flows, assets, and setup scaffolding.
greentic-flow wizardEditing flows inside an existing pack or bundle through a declarative action plan.

For a new bundle, start at the bundle level:

Terminal window
gtc wizard --answers deep-research-demo-create-answers.json --out ./deep-research-demo

For a flow inside an existing pack, let greentic-flow create or edit the .ygtc file:

Terminal window
greentic-flow new --flow flows/main.ygtc --id main --type messaging --name "Research Assistant"
greentic-flow add-step --flow flows/main.ygtc \
--node-id format_answer \
--component oci://ghcr.io/greenticai/components/templates:0.1.2 \
--operation text \
--mode config \
--routing-reply

The CLI handles the repetitive parts: node insertion, route rewiring, component manifest lookup, config-flow prompts, answer validation, and sidecar updates.

Coding agents work best when they use the same schemas as the CLI instead of inventing YAML by hand.

Ask the agent to:

  1. Inspect the existing flow and its sidecar.

  2. Fetch the wizard plan schema:

    Terminal window
    greentic-flow wizard --schema
  3. Fetch the component answer schema for each component step:

    Terminal window
    greentic-flow component-schema oci://ghcr.io/greenticai/components/templates:0.1.2 --mode default
  4. Write a plan file with actions such as add-flow, add-step, update-step, or delete-step.

  5. Apply it non-interactively:

    Terminal window
    greentic-flow wizard ./my-pack --answers flow-plan.json
  6. Run validation:

    Terminal window
    greentic-flow doctor ./my-pack

This is the recommended path for larger changes. The agent can reason about the intent, but greentic-flow still performs the schema-aware mutations and catches invalid routing or missing answers.

Components can ship dev_flows that describe how to create their own flow nodes. The component-templates pack includes:

component-templates/flows/custom.ygtc
id: ai.greentic.component-templates.custom
kind: component-config
description: Auto-generated custom config for ai.greentic.component-templates
nodes:
ask_config:
questions:
fields:
- id: text
prompt: Handlebars template used to render the reply
type: string
- id: output_path
prompt: Dot path where the rendered string is stored
type: string
default: text
- id: wrap
prompt: Wrap output in an object when true; emit a raw string when false
type: boolean
default: true
routing:
- to: emit_config

That means a human, CI job, or coding agent can answer component-specific questions and let the component emit the correct component.exec node. This is why generated flows are safer than copying snippets from documentation.

Validate flows before committing or packaging:

Terminal window
greentic-flow doctor flows/

Useful related commands:

Terminal window
greentic-flow doctor --json flows/main.ygtc
greentic-flow answers --component ./component-templates --operation text --name templates
greentic-flow doctor-answers --schema templates.schema.json --answers templates.example.json
greentic-flow bind-component --flow flows/main.ygtc --step format_answer --component oci://ghcr.io/greenticai/components/templates:0.1.2 --write
  1. Start with gtc wizard or a demo bundle rather than a blank directory.
  2. Use greentic-flow wizard plans for multi-step changes.
  3. Use greentic-flow add-step and update-step for component-backed nodes.
  4. Keep node IDs stable and descriptive.
  5. Prefer component config flows and answer files over handwritten payloads.
  6. Commit .ygtc files together with their .ygtc.resolve.json sidecars.
  7. Use --pin for remote components when you need reproducible builds.
  8. Run greentic-flow doctor before packaging or deployment.