Context Variables
Context variables provide access to data from various sources throughout your Compozy workflows. Understanding the context structure and data access patterns is essential for building dynamic, data-driven configurations.
Overview
Compozy's template engine automatically provides a hierarchical context structure that gives you access to:
Workflow Data
Task Outputs
Environment Variables
Collection Context
Tool & Agent Data
Global Values
Default Context Structure
Compozy automatically initializes these context fields, ensuring they're always available in your templates:
context:
env: {} # Environment variables map
input: {} # Workflow input data
output: null # Current task output (null by default)
trigger: {} # Workflow trigger context
tools: {} # Available tools registry
tasks: {} # Task execution results
agents: {} # Agent execution state
Core Context Variables
Workflow Context provides access to workflow-level data and metadata:
# Workflow input data
user_id: "{{ .workflow.input.user_id }}"
search_query: "{{ .workflow.input.query }}"
preferences: "{{ .workflow.input.user_preferences }}"
# Workflow metadata
workflow_id: "{{ .workflow.id }}"
workflow_version: "{{ .workflow.version }}"
started_at: "{{ .workflow.started_at }}"
# Workflow configuration
timeout: "{{ .workflow.config.timeout }}"
retry_policy: "{{ .workflow.config.retry_policy }}"
Common workflow patterns:
- Use
.workflow.input
for user-provided data - Use
.workflow.id
for unique workflow identification - Use
.workflow.config
for execution parameters
Advanced Context Patterns
Nested Data Access enables navigation of complex data structures:
# Deep object access
user_email: "{{ .tasks.get_user.output.profile.contact.email }}"
first_tag: "{{ .tasks.get_metadata.output.tags.0 }}"
# Safe nested access with defaults
city: "{{ .tasks.get_location.output.address.city | default 'Unknown' }}"
phone: "{{ coalesce .user.contact.phone .user.profile.phone 'No phone' }}"
# Array element access
first_result: "{{ index .tasks.search.output.results 0 }}"
last_item: "{{ index .tasks.fetch.output.items (sub (len .tasks.fetch.output.items) 1) }}"
Navigation techniques:
- Use dot notation for nested objects
- Use
.0
orindex
for array access - Use
default
for safe fallbacks - Use
coalesce
for multiple fallback options
Context in Task Types
Basic Tasks use context for simple operations:
- id: api_request
type: basic
$use: tool(local::tools.#(id=="http_client"))
with:
# Workflow input
url: "{{ .workflow.input.api_endpoint }}"
# Environment configuration
api_key: "{{ .env.API_KEY }}"
# Previous task output
user_id: "{{ .tasks.authenticate.output.user_id }}"
# Dynamic headers
headers:
Authorization: "Bearer {{ .tasks.authenticate.output.token }}"
Content-Type: "application/json"
X-Request-ID: "{{ .workflow.id }}"
Best Practices
Use Meaningful Variable Names
Always use descriptive names that clearly indicate what data you're accessing:
# ✅ Good - descriptive access
user_email: "{{ .tasks.get_user_profile.output.email }}"
auth_token: "{{ .tasks.authenticate_user.output.access_token }}"
# ❌ Avoid - unclear references
data: "{{ .tasks.task1.output.data }}"
result: "{{ .tasks.step2.output }}"
Provide Fallback Values
Always provide sensible defaults to prevent template errors:
# Always provide sensible defaults
timeout: "{{ .workflow.config.timeout | default 30 }}"
retries: "{{ .env.MAX_RETRIES | default 3 | int }}"
user_name: "{{ .tasks.get_user.output.name | default 'Guest' }}"
Validate Context Before Use
Check data existence before accessing nested structures:
# Check existence before accessing nested data
safe_access: |
{{- if and .tasks.api_call.output (hasKey .tasks.api_call.output "data") -}}
{{ .tasks.api_call.output.data.result }}
{{- else -}}
null
{{- end -}}
Use Type-Appropriate Conversions
Convert data types as needed for proper processing:
# Convert types as needed
port_number: "{{ .env.PORT | default '3000' | int }}"
debug_flag: "{{ .env.DEBUG | default 'false' | bool }}"
timeout_float: "{{ .config.timeout | default '30.5' | float64 }}"
Document Complex Context Usage
Add comments to explain complex context access patterns:
# Document complex context access patterns
user_notification_config:
# User's preferred notification method from profile
method: "{{ .tasks.get_user_profile.output.notifications.method | default 'email' }}"
# Fallback to workflow input if profile incomplete
email: "{{ coalesce .tasks.get_user_profile.output.email .workflow.input.email }}"
# Environment-based configuration
service_url: "{{ .env.NOTIFICATION_SERVICE_URL }}"
# Dynamic content based on user type
template: |
{{- if eq .tasks.get_user_profile.output.type "premium" -}}
premium_notification
{{- else -}}
standard_notification
{{- end -}}
References
Context variables are the foundation of dynamic Compozy workflows. Understanding how to access and manipulate this data is essential for building powerful, data-driven templates.