# Basic: Variable Interpolation InTouch has **exactly one** interpolation syntax, used everywhere — IML workflows, native tasks, one-shots, monitors, and IML tool steps. Learn it once; it's the same in every layer. ## The one syntax ``` {{name.field}} ``` - **Double** curly braces `{{ }}`. That's the only InTouch interpolation form. - `{{name.field}}` references an output published by a prior **task** (in a workflow) or **step** (in a tool), addressed by its `name:` and the field it published. Exactly two parts, one dot, **no prefix** (`task.`/`tasks.`/`steps.` are all wrong). - `${ }` is **NOT** InTouch syntax. It is left untouched for the shell — so `${HOME}` inside a script stays a shell variable. Never use `${ }` to reference InTouch data. - An unresolved or malformed reference **fails loud** (the workflow/tool errors with a "here's what's available" message). Nothing is ever delivered as literal `{{...}}` text. ## Reserved namespaces A few names are reserved for context lookups (don't name a task/step one of these): | Reference | Resolves to | |---|---| | `{{input.name}}` | a IML **tool's** declared input | | `{{credential.name}}` | a property of the tool's bound credential | | `{{workflow.field}}` | workflow metadata (`name`, `id`, `fqnName`, `areaName`, `trackName`, …) | | `{{args.key}}` | caller-supplied invocation input (a monitor's `run_jobfile.args`, `/run` args) | | `{{env.NAME}}` | an environment / runtime-environment variable | | `{{date(pattern)}}` | current date/time, e.g. `{{date(yyyy-MM-dd)}}` → `2026-05-27` | Everything else — `{{name.field}}` — is a prior task/step output. ## How to know what a task/step publishes Every tool's `get_help(…)` lists its **published outputs** — the fields you can reference downstream. Common examples: | Tool | Common published fields | |---|---| | `http` | `statusCode`, `body`, `headers` | | `sql` (statement) | `rowsAffected`, `output` | | `sql` (export) | `outputFile`, `rowCount` | | `runtimeenv` | `exitCode`, `stdout`, `stderr`, `outputFile` | | `anthropic` / `openai` | `completion`, `inputTokens`, `outputTokens` | | `rss-reader` | `entries`, `entryCount` | | `hacker-news-top` | `summary`, `stories`, `count` | | `ssh` | `stdout`, `stderr`, `exitCode` | Illustrative only — call `get_help(…)` for the exact tool. **Do not guess field names.** ## Correct usage (workflows and tools — identical) A workflow chaining two tasks: ```json { "tasks": [ { "name": "fetch-feed", "tool": "http", "properties": { "url": "https://example.com/feed.xml", "method": "GET" } }, { "name": "notify", "tool": "message", "properties": { "userNames": [ "intouch" ], "subject": "Feed status {{date(yyyy-MM-dd)}}", "body": "HTTP {{fetch-feed.statusCode}}" } } ] } ``` A tool chaining two steps (same `{{ }}`, plus `{{input.x}}`): ```json { "steps": [ { "name": "fetch", "type": "http", "url": "https://api.example.com/{{input.endpoint}}" }, { "name": "parse", "type": "python", "script": "parse.py" } ] } ``` ## What does NOT work | Wrong | Right | Why | |---|---|---| | `${fetch-feed.statusCode}` | `{{fetch-feed.statusCode}}` | `${ }` is shell, never InTouch. Use `{{ }}`. | | `{{task.fetch-feed.statusCode}}` | `{{fetch-feed.statusCode}}` | No `task.` prefix. | | `{{steps.fetch.body}}` | `{{fetch.body}}` | No `steps.` prefix either. | | `{{fetch-feed.body.length}}` | (compute in a downstream task/step) | One dot only — no nested paths, filters, or transforms. | | `{{ fetch-feed.statusCode }}` | `{{fetch-feed.statusCode}}` | No spaces inside the braces. | If you need transforms, nested access, conditionals, or filters, prefer a tool that publishes the value you actually want — most hub tools already flatten their output into named bindings, so the transform disappears. Search the hub before writing anything. Writing a `runtimeenv`/`python` step purely to reshape another tool's output is a workaround for a resolver limitation, not a pattern to reach for: it hard-codes one job's field names into a script that travels nowhere. If you do need one, say plainly that you are authoring a step because no published binding carries the value. ## Multi-line content Use a IML literal block `|` and reference variables with `{{ }}`. InTouch substitutes them **before** the script runs, so the script receives literal resolved values: ```json - name: process tool: runtimeenv properties: runtimeEnvName: python scriptContent: | status = "{{fetch-feed.statusCode}}" print(f"Got {status}") ``` (Don't write `${fetch-feed.statusCode}` here expecting InTouch to fill it — to InTouch that's just shell text; only `{{ }}` is interpolated.) ## Cross-reference - After authoring, validate per [validation.md](./validation.md) - Workflow format: [../build/workflow-file.md](../build/workflow-file.md) · Tool format: [../build/iml-tool.md](../build/iml-tool.md)