Appearance
Placeholders
A placeholder is a name in curly braces that is replaced with a live value when the automation runs. Hello {actor.name}, {card.title} is due {card.due_date} becomes a real sentence the moment the run reaches that node.
Every text field in the builder accepts them, and the fields that do have a picker button. The picker lists the tokens that make sense at that point in the graph, including the outputs of every node upstream of the one you are editing.
The rules
- A token is
{a name}, made of letters, digits, underscores and dots. - A token that resolves to nothing becomes an empty string.
- A token Truetask does not recognise is left alone, braces and all, so literal braces survive.
- A field or relation name may contain spaces; its key never does, because spaces become underscores. A field called
Deal valueis{card.xattr.Deal_value}. - A node's own name is the key other nodes address it by. Node names are lowercase snake_case, and the builder converts spaces and hyphens for you.
The task
Available whenever the run has a task in focus, which is every task trigger and anything after a Target Card or Target Linked Record node.
| Token | Value |
|---|---|
{card.id} | ID |
{card.title} | Title |
{card.description} | Description |
{card.priority} | Priority |
{card.list} | List |
{card.board} | Board |
{card.start_date} | Start date |
{card.due_date} | Due date |
{card.created} | Created |
{card.updated} | Updated |
{card.archived} | true or false |
{card.completed} | true or false |
{card.url} | A link to the task |
{card.assignee.email} | Assignee emails, comma separated |
{card.watchers.email} | Watcher emails, comma separated |
The board
| Token | Value |
|---|---|
{board.id} | ID |
{board.name} | Name |
{board.summary} | Summary |
{board.status} | Board status |
{board.status_kind} | Board status kind |
{board.start} | Board start date |
{board.end} | Board end date |
{board.icon} | Icon |
{board.key} | Board key, the prefix on task keys |
{board.created} | Created |
{board.url} | A link to the board |
{board.xattr.<Field_name>} | A board-level custom field's value |
Custom fields and linked records
| Token | Value |
|---|---|
{card.xattr.<Field_name>} | The task's value for that custom field |
{card.xattr.<Relation>.title} | The title of the record linked through that relation field |
{card.xattr.<Relation>.id} | Its id |
{card.xattr.<Relation>.<Field_name>} | A custom field on the linked record |
A relation with several targets joins them with a comma, in link order. The picker lists one entry per relation field on the board, so you rarely need to type these by hand. See Custom fields.
The person who caused it
| Token | Value |
|---|---|
{actor.id} | ID |
{actor.name} | Name |
{actor.email} |
Clock and calendar
Available to every trigger, and the only context a scheduled run has when it runs for the board. Times are in the run's timezone: the one the schedule pinned, otherwise the workspace default, otherwise UTC.
| Token | Value |
|---|---|
{now} | Date and time now, YYYY-MM-DD HH:MM |
{now.iso} | Date and time now in UTC, ISO 8601 |
{now.time} | Time now, HH:MM |
{now.hour} | Hour now, 00 to 23 |
{now.tz} | The timezone of this run |
{today} and {today.iso} | Today's date, YYYY-MM-DD |
{today.weekday} | Weekday name, such as Monday |
{today.weekday_num} | Weekday number, Sunday is 0 |
{today.month} | Month number |
{today.year} | Year |
{today.week} | ISO week number |
{today+7} | Seven days from today |
{today-1} | Yesterday |
{today+N} and {today-N} take any whole number of days.
Trigger payloads
These are filled in only by the trigger they belong to, and are empty otherwise.
Board status change
{board_status.old}, {board_status.new}, {board_status.old_kind}, {board_status.new_kind}
Board field change
{board_field.name}, {board_field.old}, {board_field.new}
Milestone
{milestone.id}, {milestone.name}, {milestone.date}
Note
{note.id}, {note.title}, {note.path}, {note.folder}, {note.content}, {note.status}, {note.url}, {note.changed}
A note comment also fills {comment.id}, {comment.message} and {comment.author}.
Note publication
{publication.id}, {publication.slug}, {publication.title}, {publication.scope}, {publication.url}
Agent handoff
{handoff.run_id}, {handoff.step}, {handoff.step_key}, {handoff.to_agent}, {handoff.to_agent_id}, {handoff.from_agent}, {handoff.from_agent_id}
Agent run status
{run.id}, {run.status}, {run.previous_status}, {run.agent}, {run.agent_id}, {run.summary}
Incoming webhook
| Token | Value |
|---|---|
{webhook.name} | Endpoint name |
{webhook.method} | HTTP method |
{webhook.ip} | Sender IP |
{webhook.body} | The raw body |
{webhook.body.<field>} | One field out of the body |
{webhook.query.<param>} | One query parameter |
{webhook.header.<name>} | One request header |
{webhook.files} | The files the request carried |
{webhook.files_count} | How many |
{webhook.files.0.name} | The name of the file at that position |
The endpoint picker on the trigger shows the last request it received, so you can read the field names off it and copy a placeholder straight out. See Webhooks.
Text message
{sms.from}, {sms.to}, {sms.body}, {sms.sid}, {sms.media_count}
After a Send text node: {sms_sent.to} and {sms_sent.status}.
WhatsApp
{whatsapp.from}, {whatsapp.from_name}, {whatsapp.to}, {whatsapp.body}, {whatsapp.id}
After a Send WhatsApp node: {whatsapp_sent.to} and {whatsapp_sent.status}.
Git
Filled by the git triggers.
| Token | Value |
|---|---|
{git.pr_number} | Pull request number |
{git.pr_title} | Pull request title |
{git.pr_state} | Pull request state |
{git.pr_url} | Pull request link |
{git.source_branch} | Head branch |
{git.target_branch} | Base branch |
{git.author} | Author login |
{git.repo} | Repository, owner and name |
{git.sha} | Commit SHA |
{git.commit_message} | Commit message |
{git.commit_url} | Commit link |
{git.issue_number} | Issue number |
{git.issue_title} | Issue title |
{git.issue_state} | Issue state |
{git.issue_url} | Issue link |
These are not in the picker; type them. See Git integration.
Output from an upstream node
Nodes that produce something expose it under their own node name. The picker adds a group per upstream node, so you can click the token instead of typing it.
| Node | Tokens |
|---|---|
| HTTP Request | {http.<name>} the whole response, {http.<name>.status}, {http.<name>.body}, {http.<name>.headers.<header>} |
| Parse JSON and Parse XML | {parsed.<name>} the whole result, {parsed.<name>.<variable>} for each extract you named |
| Read Note, Write Note, Update Note | {notes.<name>}, {notes.<name>.content}, {notes.<name>.count}, {notes.<name>.title}, {notes.<name>.path}, {notes.<name>.notes.0.title} |
| Agent | {agent.output} for the most recent one, {agent.output.<node_id>} for a specific one |
| Quick AI actions | {ai.output} for the most recent one, {ai.output.<node_id>} for a specific one |
{agent.output} and {ai.output} point at the same text, so either spelling works. Header names are lowercase.
Inside a For Each loop
| Token | Value |
|---|---|
{loop.item} | The current item |
{loop.item.<path>} | A dotted path into the current item |
{loop.index} | The zero-based counter |
{loop.total} | How many items there are |
When the loop walks tasks rather than JSON, it also swaps the focus task each turn, so {card.title} and the rest follow the loop.
Comparing values
A Condition or Filter node in Card field mode picks its left side from a list. Switch it to Expression mode and the left side is a text field that takes placeholders, so you can compare anything, including two upstream outputs: {parsed.lookup.is_active} equals true.
The right side is a text field too, so both sides can be placeholders. See Actions and logic for the operators each field type offers.
Seeing what is actually there
Drop a Debug node anywhere in the graph and run the automation. It snapshots the placeholders available at that point into the run log, and does nothing else. See Runs and logs.

