7. Install the after-hours alarm

The second half of the job is not an immediate action. It is a flow that must remain installed and wait for an event.

The examples guide supplies this real flow:

{
  "name": "dock door alert",
  "trigger": {
    "event": "sensor.door_dock.opened"
  },
  "steps": [
    {
      "id": "check",
      "do": "branch",
      "when": {
        "gt": [
          "$.world.time",
          "21:00"
        ]
      },
      "then": [
        {
          "id": "alert",
          "do": "call",
          "device": "notify.facilities",
          "action": "send",
          "with": {
            "message": "Dock door opened after hours"
          }
        }
      ]
    }
  ]
}

Make the near-miss on purpose: send a triggered flow as immediate. The response below is from a published fresh-session capture:

Request
{
  "tool": "run_flow",
  "arguments": {
    "flow": {
      "name": "dock door alert",
      "trigger": {
        "event": "sensor.door_dock.opened"
      },
      "steps": [
        {
          "id": "check",
          "do": "branch",
          "when": {
            "gt": [
              "$.world.time",
              "21:00"
            ]
          },
          "then": [
            {
              "id": "alert",
              "do": "call",
              "device": "notify.facilities",
              "action": "send",
              "with": {
                "message": "Dock door opened after hours"
              }
            }
          ]
        }
      ]
    },
    "mode": "immediate",
    "expected_catalog_version": "cv_590fefad56a7a504",
    "trace_level": "full"
  }
}
Response
{
  "run_id": "run_0003",
  "outcome": {
    "ok": false,
    "status": "validation_error",
    "error": "this flow declares a trigger; mode \"immediate\" would silently ignore it"
  },
  "diagnostics": [
    {
      "severity": "error",
      "code": "bad_trigger",
      "path": "/trigger",
      "message": "mode \"immediate\" runs the steps once, now. It does not install the trigger",
      "hint": "use mode \"deploy\" to install this flow as an automation, or remove 'trigger' to run the steps immediately"
    }
  ]
}

run_id values are session-scoped and are not gap-free. The value above belongs to the published capture.

Now change only the mode. The captured deployment result follows:

Request
{
  "tool": "run_flow",
  "arguments": {
    "flow": {
      "name": "dock door alert",
      "trigger": {
        "event": "sensor.door_dock.opened"
      },
      "steps": [
        {
          "id": "check",
          "do": "branch",
          "when": {
            "gt": [
              "$.world.time",
              "21:00"
            ]
          },
          "then": [
            {
              "id": "alert",
              "do": "call",
              "device": "notify.facilities",
              "action": "send",
              "with": {
                "message": "Dock door opened after hours"
              }
            }
          ]
        }
      ]
    },
    "mode": "deploy",
    "expected_catalog_version": "cv_590fefad56a7a504",
    "trace_level": "full"
  }
}
Response
{
  "run_id": "run_0004",
  "outcome": {
    "ok": true,
    "status": "success",
    "error": null
  },
  "output": {
    "ref": "auto_001",
    "trigger": {
      "event": "sensor.door_dock.opened"
    }
  },
  "trace": {
    "run_id": "run_0004",
    "level": "full",
    "steps": [
      {
        "id": "deploy",
        "input": null,
        "output": {
          "ref": "auto_001",
          "trigger": {
            "event": "sensor.door_dock.opened"
          }
        },
        "outcome": {
          "ok": true,
          "status": "success",
          "error": null
        }
      }
    ]
  }
}

Promotion is different. promote_flow stores an on-demand program callable by program_ref; it does not install a trigger.

What this taught

immediate runs now. deploy installs future behavior. A refusal can be a useful value whose diagnostic names the repair.

See Outcomes and Part II ยง6.5.7.