Constants and Expressions
Constants and expressions allow you to define reusable values in your configuration. Constants are static values, while expressions are dynamically evaluated using Python.
Constants
Define constants using the constants: key. Constants are static values that don't change during execution.
Global Constants
Defined under dyngle: and available to all operations:
dyngle:
constants:
environment: production
region: us-west-2
api-url: https://api.example.com
operations:
deploy:
steps:
- echo "Deploying to {{environment}} in {{region}}"
Local Constants
Defined within a specific operation:
dyngle:
operations:
greet:
constants:
greeting: Hello
name: World
steps:
- echo "{{greeting}}, {{name}}!"
Local constants override global constants with the same name.
Expressions
Expressions are Python code snippets that compute dynamic values. They're evaluated in real-time using the Python interpreter with a controlled set of available functions and variables specific to Dyngle.
Basic Usage
Define expressions that evaluate to values:
dyngle:
operations:
greet:
expressions:
greeting: "'Hello ' + name + '!'"
steps:
- echo "{{greeting}}"
Run it:
echo "name: Alice" | dyngle run greet
Output:
Hello Alice!
Expressions vs Constants
An expression is like a constant that is evaluated dynamically:
dyngle:
constants:
static-time: "2024-01-01" # Always the same
expressions:
current-time: "datetime.now()" # Evaluated each time
Global Expressions
Defined under dyngle: and available to all operations:
dyngle:
expressions:
timestamp: "datetime.now()"
author: "'Francis Potter'"
operations:
log:
steps:
- echo "[{{timestamp}}] Log by {{author}}"
Local Expressions
Defined within a specific operation:
dyngle:
operations:
say-hello:
expressions:
count: "len(name)"
steps:
- echo "Hello {{name}}! Your name has {{count}} characters."
Local expressions override global expressions with the same name.
Available Functions and Names
Expressions evaluate in a context that includes a subset of Python's standard features plus some Dyngle-specific functions. This controlled environment ensures expressions are powerful yet predictable.
Referencing Context Values
Values from the operation context can be referenced directly as Python variables:
dyngle:
operations:
greet:
expressions:
message: "'Hello ' + name"
steps:
- echo "{{message}}"
Hyphenated Names
YAML keys can contain hyphens. To reference them in expressions:
Option 1: Replace hyphens with underscores:
dyngle:
operations:
greet:
expressions:
message: "'Hello ' + first_name" # References 'first-name'
steps:
- echo "{{message}}"
Option 2: Use the get() function:
dyngle:
operations:
greet:
expressions:
message: "'Hello ' + get('first-name')"
steps:
- echo "{{message}}"
Dyngle-Specific Functions
get()
Retrieve values from the operation context by name:
dyngle:
expressions:
full-greeting: "'Hello ' + get('first-name') + ' ' + get('last-name')"
The get() function can also reference other expressions:
dyngle:
expressions:
greeting: "'Hello'"
full-greeting: "get('greeting') + ' ' + name"
format()
Render a template string using the current operation context:
dyngle:
values:
first-name: Alice
last-name: Smith
operations:
greet:
expressions:
full-greeting: "format('Hello, {{first-name}} {{last-name}}!')"
steps:
- echo "{{full-greeting}}"
The format() function supports all template syntax, including nested properties:
dyngle:
operations:
weather-report:
expressions:
report: "format('Temperature in {{location.city}} is {{weather.temperature}} degrees')"
steps:
- echo "{{report}}"
dtformat()
Format datetime objects as strings:
dyngle:
expressions:
now: "datetime.now()"
timestamp: "dtformat(get('now'), '%Y-%m-%d %H:%M:%S')"
operations:
log:
steps:
- echo "[{{timestamp}}] Event occurred"
PurePath()
Work with operating system paths:
dyngle:
operations:
git-dir:
expressions:
result: PurePath(cwd) / '.git'
steps:
- pwd => cwd
returns: result
Note that command steps can be used for I/O operations while using Python to manipulate paths and strings.
dyngle:
operations:
show-tests:
expressions:
test-dir: PurePath(cwd) / 'test'
test-files: '[f.strip() for f in test_files_text.split("\n")]'
result:
test-dir: get('test-dir')
test-files: get('test-files')
steps:
- pwd => cwd
- ls -1 {{test-dir}} => test-files-text
returns: result
Runtime Declarations
Runtime declarations are automatically provided values that reflect runtime execution context. Unlike constants and expressions defined in your configuration, these are set by the Dyngle runtime based on how the operation was invoked.
runtime.args
Command-line arguments passed to dyngle run are available under runtime.args:
dyngle:
operations:
greet:
expressions:
name: "get('runtime.args.0') or 'World'"
steps:
- echo "Hello {{name}}!"
Run with:
dyngle run greet Alice
Output:
Hello Alice!
Important notes:
runtime.argsis only available in theruncommand, not in MCP operations- Args are not automatically passed to sub-operations; use
send:to pass them explicitly - Access via
get('runtime.args.N')for safe access with defaults - Access via
runtime.args.Nin templates when you know the arg exists
The runtime namespace is reserved for future runtime-provided values (environment info, execution metadata, etc.).
Environment and System Functions
getenv()
Access environment variables:
dyngle:
operations:
show-env:
expressions:
home-dir: "getenv('HOME', '/default/path')"
api-key: "getenv('API_KEY') or 'not-set'"
steps:
- 'echo "Home directory: {{home-dir}}"'
- 'echo "API Key: {{api-key}}"'
getcwd()
Get the current working directory:
dyngle:
operations:
show-cwd:
expressions:
current-dir: "getcwd()"
parent-dir: "str(PurePath(getcwd()).parent)"
steps:
- 'echo "Working in: {{current-dir}}"'
- 'echo "Parent: {{parent-dir}}"'
Data Serialization Functions
to_json()
Convert Python data structures to JSON strings:
dyngle:
operations:
create-config:
expressions:
config-data:
server: "format('{{host}}')"
port: "int(get('port'))"
enabled: "True"
json-output: "to_json(get('config-data'))"
steps:
- echo "{{json-output}}"
from_json()
Parse JSON strings into Python data structures:
dyngle:
operations:
parse-json:
expressions:
parsed: "from_json(json_string)"
server-host: "get('parsed')['server']"
steps:
- 'echo "Server: {{server-host}}"'
to_yaml()
Convert Python data structures to YAML strings:
dyngle:
operations:
create-yaml:
expressions:
config-data:
database: "format('{{db-name}}')"
timeout: "30"
yaml-output: "to_yaml(get('config-data'))"
steps:
- echo "{{yaml-output}}"
from_yaml()
Parse YAML strings into Python data structures:
dyngle:
operations:
parse-yaml:
expressions:
parsed: "from_yaml(yaml_string)"
db-name: "get('parsed')['database']"
steps:
- 'echo "Database: {{db-name}}"'
Python Features
Expressions support a subset of Python's features:
Built-in Types and Functions
str(),int(),float(),bool(),len(), etc.
Standard Library Modules
- datetime - Date and time operations (
datetime.now(),datetime.date(), etc.) - math - Mathematical functions (
math.pi,math.sqrt(), etc.) - re - Regular expression operations (
re.match(),re.search(),re.sub(), etc.) - PurePath() - Path manipulation operations (no file I/O)
- json - JSON serialization via
to_json()andfrom_json()functions - yaml - YAML serialization via
to_yaml()andfrom_yaml()functions - os - Environment and system operations via
getenv()andgetcwd()functions
Data Structures
- Lists, dictionaries, tuples
- List comprehensions
- Dictionary comprehensions
Operators
- Arithmetic:
+,-,*,/,//,%,** - Comparison:
==,!=,<,>,<=,>= - Logical:
and,or,not - String: concatenation, formatting
Expression Examples
String Manipulation
dyngle:
expressions:
uppercase-name: "name.upper()"
initials: "'.'.join([word[0] for word in name.split()])"
Mathematical Operations
dyngle:
expressions:
circle-area: "math.pi * radius ** 2"
rounded: "round(get('circle-area'), 2)"
Date and Time
dyngle:
expressions:
now: "datetime.now()"
today: "get('now').date()"
formatted-date: "dtformat(get('now'), '%B %d, %Y')"
List Operations
dyngle:
values:
numbers: [1, 2, 3, 4, 5]
expressions:
doubled: "[n * 2 for n in get('numbers')]"
sum-numbers: "sum(get('numbers'))"
max-number: "max(get('numbers'))"
Conditional Logic
dyngle:
expressions:
environment: "get('env') if get('env') else 'development'"
log-level: "'DEBUG' if get('environment') == 'development' else 'INFO'"
Nested Structure Syntax
Constants and expressions can contain YAML structures. This allows defining hierarchical data that can be referenced using context paths.
For Constants
Use nested YAML structures directly:
dyngle:
constants:
server:
host: api.example.com
port: 443
ssl: true
database:
name: mydb
connection:
- host: db.example.com
- port: 5432
operations:
connect:
steps:
- echo "Connecting to {{server.host}}:{{server.port}}"
- 'echo "Database: {{database.name}}"'
For Expressions
Strings within YAML structures can be referenced and evaluated as separate expression:
dyngle:
expressions:
configure:
server:
host: "format('{{server-host}}')"
port: "int(get('server-port'))"
database:
name: "format('{{db-name}}')"
connection:
- "format('{{db-host}}')"
- "int(get('db-port'))"
Important Notes
- Each string in an expression structure is evaluated as Python code
- Numbers, booleans, and None pass through unchanged in both constants and expressions
- For string literals in expressions, use Python string syntax:
"'literal string'" - Access nested properties using context paths:
{{config.server.host}} - Access array elements in expressions using Python brackets:
get('coordinates')[get('location-index')]
Mixed Example
Combining constants and expressions with nested structures:
dyngle:
constants:
defaults:
timeout: 30
retries: 3
expressions:
runtime:
timestamp: "datetime.now()"
timeout: "get('defaults'.timeout') * 2"
config:
retry-count: "get('defaults.retries')"
enabled: "True"
operations:
process:
steps:
- 'echo "Timeout: {{runtime.timeout}}"'
- 'echo "Retries: {{runtime.config.retry-count}}"'
Context paths
Both constants and expressions with nested structures can be accessed using context paths in:
- Templates:
{{config.server.host}} - Expressions:
get('config.server.host')or via variables if hyphen-free returns::config.server.host
dyngle:
constants:
api:
endpoint: https://api.example.com
version: v1
operations:
call-api:
returns: api.endpoint
expressions:
full-url: "get('api.endpoint') + '/' + get('api.version')"
steps:
- echo "Calling {{full-url}}"