Skip to main content

Guards

Guards evaluate conditions and decide whether an action should run for each record, acting as quality checkpoints in your workflow.

Syntax

- name: my_action
guard:
condition: "expression"
on_false: "skip" | "filter"
FieldTypeDefaultDescription
conditionstringRequiredExpression evaluated against upstream data
on_falsestringfilterAction when condition is false
passthrough_on_errorbooleantruePass record through if evaluation fails

on_false Options

ValueDescription
skipAction skipped, record continues to downstream actions
filterRecord removed from workflow entirely

Condition Expressions

Comparison Operators

guard:
condition: "score > 85"
condition: "status == 'approved'"
condition: "facts != []"
OperatorDescription
==, !=Equality
>, >=, <, <=Comparison
and, or, notLogical

Advanced Operators

OperatorExample
INstatus IN ["active", "pending"]
NOT INcategory NOT IN ["spam"]
CONTAINStags CONTAINS "important"
LIKEname LIKE "prod_*"
BETWEENscore BETWEEN 50 AND 100
IS NULLdescription IS NULL

Boolean Values

Boolean keywords are case-insensitive, matching SQL convention:

guard:
condition: 'passes_filter == true' # valid
condition: 'passes_filter == True' # valid
condition: 'passes_filter == TRUE' # valid

Prefer explicit comparison over a bare field reference for boolean fields. A bare reference evaluates using Python truthiness — this fails silently when the upstream action stores "false" as a string (which is truthy) rather than a Python bool:

# Fragile — string "false" is truthy, so the guard never filters
condition: 'passes_filter'

# Explicit — correct regardless of whether the value is a bool or a string
condition: 'passes_filter == true'

Built-in Functions

guard:
condition: 'len(items) > 0'
condition: 'max(scores) >= 85'

Supported: len(), str(), int(), float(), abs(), min(), max()

Examples

Filter Empty Results

- name: canonicalize_facts
dependencies: fact_extractor
guard:
condition: 'candidate_facts_list != []'
on_false: "filter"

Skip Optional Processing

- name: enhance_summary
guard:
condition: 'needs_enhancement == true'
on_false: "skip"

Quality Gate

- name: generate_final_output
guard:
condition: 'quality_score >= 85'
on_false: "filter"

Context Access

Guards can access:

SourceSyntax
Direct fieldcandidate_facts_list
Specific actionextract_facts.count
Context scope observednum_similar_facts
- name: validate
context_scope:
observe:
- group_by_similarity.num_similar_facts
guard:
condition: 'num_similar_facts != 1'
on_false: "skip"

Downstream Behavior

How guard results affect downstream actions in a multi-action workflow:

on_falseOutput recordDownstream actions
skipOriginal content preserved, metadata.reason: "guard_skip"Process normally — each action evaluates its own guard independently
filterRecord excluded from outputNever sees it — record is removed from the pipeline

Skipped records flow downstream

When Action A skips a record (on_false: skip), Action B still receives it and can process it with its own LLM call. Each action's guard is independent:

actions:
- name: extract_facts
guard:
condition: 'status == "active"'
on_false: "skip" # Inactive records pass through with original content

- name: generate_summary
dependencies: extract_facts
# Receives ALL records from extract_facts, including skipped ones
# Can define its own guard or process everything

Upstream failures are short-circuited

When an upstream action fails for some records (e.g., batch API errors), those records are marked with _unprocessed: true and automatically skipped by all downstream actions — no context loading, prompt rendering, or LLM calls are wasted. These records are preserved in the output for lineage traceability.

Error Handling

By default, if a guard condition fails to evaluate (missing field, parse error), the record is passed through rather than rejected. Set passthrough_on_error: false to apply the configured on_false behavior instead:

guard:
condition: 'passes_filter == true'
on_false: filter
passthrough_on_error: false # filter the record if evaluation fails
tip

When a guard silently lets records through unexpectedly, check target/errors.json for G002 events — these indicate evaluation failures that were swallowed by passthrough_on_error: true.

Limitations

  • No external calls - Guards can't make API requests
  • Limited functions - Only built-in functions available
  • Not supported with File granularity - Guards evaluate per-record
  • Single expression - Complex logic should use tool actions
warning

Guards are not supported with File granularity. Implement filtering logic within your tool function instead.

See Also