ai-loop-observe-condition-action-pattern

Status: IN

FTL2 AI-loop rules follow an observe → condition → action pattern: the loop runs `observe` to gather state, calls `condition(state)` to decide whether to act, and calls `action(ftl)` if the condition returns True.

Source: entries/2026/05/11/deployments-stargate-rules-harden_stargate_ssh.md

Example

# From cloudflare-stargate/rules/ensure_stargate_linode.py
observe = [
    {"name": "existing_linodes", "module": "community.general.linode_v4",
     "params": {"label": "stargate", "state": "present"}}
]

async def condition(state: dict) -> bool:
    linode = state.get("existing_linodes", {})
    if linode.get("failed"):
        return True
    instance = linode.get("instance", {})
    if not instance or instance.get("status") != "running":
        return True
    return False

async def action(ftl) -> None:
    result = await ftl.community.general.linode_v4(
        label="stargate", type="g6-standard-1", region="us-east",
        image="private/37121878", state="present",
    )
    ip = result.get("instance", {}).get("ipv4", [None])[0]
    if ip:
        await ftl.wait_for(host=ip, port=22, timeout=300)

JSON