# Responding to action results

Tasks can react to the results of their own actions by subscribing to the **mechanic/actions/perform** event topic. This enables multi-step workflows: a task makes an HTTP request, then inspects the response and decides what to do next. Or a task creates a Shopify resource, then uses the returned ID in a follow-up action.

Because actions run asynchronously ([like all Mechanic runs](/core/runs.md)), their results aren't available during the Liquid rendering that defined them. Instead, Mechanic delivers action results back to the task as a new event. To use this, add a task subscription to the **mechanic/actions/perform** event topic. When a task includes this subscription, Mechanic will generate an event with that topic for every action that the task completes. This event will only ever be responded to by the task that generated it; it will never be sent to other tasks.

If you don't need the follow-up event for a particular action (for example, when you know the work is fire-and-forget or you're avoiding loops), set `__perform_event: false` on that action. The action still runs; Mechanic just skips emitting `mechanic/actions/perform` for it.

Common use cases:

* Evaluating [HTTP](/core/actions/http.md) response codes or payloads
  * See [Working with external APIs](/techniques/working-with-external-apis.md)
* Evaluating the results of [Shopify](/core/actions/shopify.md) GraphQL mutations
* Using content from generated [Files](/core/actions/files.md)

{% hint style="info" %}
The [Echo action](/core/actions/echo.md) does not generate mechanic/actions/perform events.
{% endhint %}

## Inspecting the context

Events with the topic mechanic/actions/perform are, by nature, always [child events](/core/events/parent-and-child-events.md). As such, their `event` variable contains a reference to the event's parent. This means a task may use `event.parent.data` to access all the data that informed the construction of the action in question. (Note that only the previous 5 generations of parents are available.)

A mechanic/actions/perform event also provides task runs with an `action` variable (containing the same information available in `event.data`). This variable contains the original [action object](/core/tasks/code/action-objects.md) (including its type, options, and meta information), and data from the run in which the action was performed.

Common sources of information for followup task runs:

* `action.options` — the original options defined for the action
* `action.run.ok` — `true` or `false`, indicating the action's success
* `action.run.result` — the value (if any) generated by the action run
* `action.run.error` — the error (if any) raised during the action run
* `action.meta` — the [meta information](/core/tasks/code/action-objects.md#meta) given in the action's definition

{% hint style="warning" %}
It's important to specifically account for the mechanic/actions/perform topic when writing task code, minding the fact that improper composition could result in an infinite loop.

Mechanic will step in and forcibly fail subsequent task runs that contain results identical to their predecessors.
{% endhint %}

## Example

This example cycles between three different modes of operation, depending on the [meta information](/core/tasks/code/action-objects.md#meta) recorded in the action definition. And, by checking on `action.run.ok` at the very beginning, the task is also able to "break" into failure-handling mode, in which an email is sent to an administrator.

**Subscriptions**

```
mechanic/user/trigger
mechanic/actions/perform
```

**Code**

```liquid
{% if action.run.ok == false %}
  {% action "email" %}
    {
      "to": "admin@example.com",
      "subject": "Action failure",
      "body": {{ "Alert!<br><br>" | append: action.run.error | json }}
    }
  {% endaction %}
{% elsif event.topic contains "trigger" %}
  {% action %}
    {
      "type": "cache",
      "options": ["set", "foo", "bar"],
      "meta": {
        "mode": "first"
      }
    }
  {% endaction %}
{% elsif action.meta.mode == "first" %}
  {% capture mutation %}
    mutation {
      tagsAdd(id: "gid://shopify/Customer/1234567890", tags: ["processed"]) {
        userErrors { field, message }
      }
    }
  {% endcapture %}

  {% action %}
    {
      "type": "shopify",
      "options": {{ mutation | json }},
      "meta": {
        "mode": "second"
      }
    }
  {% endaction %}
{% elsif action.meta.mode == "second" %}
  {% action "echo", "done" %}
{% endif %}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://learn.mechanic.dev/techniques/responding-to-action-results.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
