Understand how Scout workflows pass data between blocks through shared state — references, conditional logic, global variables, and error handling.
A Scout workflow moves data through a shared state object that’s passed from block to block. Each block reads what it needs from earlier blocks, does its job, and adds its own output back to the state for downstream blocks to use. Designing that state deliberately is what makes a workflow predictable, testable, and easy to debug.
Consider a three-block chain: an Input block, an enrich_user block that looks up account details, and a send_email block that composes a message.
{# In the enrich_user block — read from the workflow inputs #}User name: {{ inputs.user_name }}Account tier: {{ inputs.account_tier }}
{# In the send_email block — read from the enrich_user block #}Full name: {{ enrich_user.full_name }}Plan label: {{ enrich_user.plan_label }}
Each block pulls only the fields it needs. Map references explicitly rather than passing the whole state object around — when something breaks, you want to see exactly which value a block depended on.
Reference the specific fields a block needs instead of handing it the entire upstream output. Explicit mappings make failures obvious in the logs.
Use Jinja if/elif/else blocks to branch on values in your state. This is useful for routing and for shaping dynamic content.Route by account tier:
{% if inputs.account_tier == "enterprise" %} Priority support queue — SLA: 4 hours{% elif inputs.account_tier == "pro" %} Standard support queue — SLA: 24 hours{% else %} Community support — check our docs first{% endif %}
Build a dynamic prompt that adapts to the input:
You are a support assistant.{% if inputs.has_prior_conversation %}The user has contacted us before. Be warm and reference their history.{% else %}This is a new user. Introduce yourself briefly.{% endif %}User message: {{ inputs.message }}
Scout exposes built-in date and time variables you can use in any template without configuration. They’re handy for timestamps, logging, and report headers.
Variable
Example output
{{ __exp_global.current_date }}
2025-06-15
{{ __exp_global.current_time }}
14:23:01
{{ __exp_global.current_datetime }}
2025-06-15 14:23:01
{{ __exp_global.current_time_utc }}
21:23:01 UTC
{{ __exp_global.current_time_pacific }}
14:23:01 PDT
For example:
[{{ __exp_global.current_datetime }}] User {{ inputs.user_id }} submitted requestReport generated on {{ __exp_global.current_date }}
A few habits keep workflow state clean as it grows:
Keep payloads small. Pass only the fields a block actually needs, not the whole state object.
Use stable key names. Renaming an output field silently breaks every downstream reference to it.
Normalize once. Clean and format data in one early block, then reuse the normalized values everywhere downstream.
Prefer structured output over string building. Return structured data like { "user_id": "abc", "status": "active" } rather than a formatted string — it’s far easier to branch on later.