> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.aibydna.com/llms.txt
> Use this file to discover all available pages before exploring further.

# request_trigger_plan

> Ask Aether which systems in your environment should run.

Asks Aether what each system in your environment should do, based on the Deltas reported since the last plan and what already ran. Returns a Trigger Plan with one decision per system.

> [!WARNING]
>
> Only the environment's **top-level orchestrator** can call this, with its own API key. Any other key gets `403`.

## When to use it

Call it from the orchestrator before dispatching work, e.g. at the start of a run or on a schedule, to skip systems whose work is already up to date.

## Signature

```python theme={null}
async def request_trigger_plan(self, plan: TriggerPlanCreate) -> TriggerPlanOut
```

| Argument | Type | Description |
| - | - | - |
| `plan` | `TriggerPlanCreate` | The request. |

### `TriggerPlanCreate`

| Field | Type | Required | Description |
| - | - | - | - |
| `intent` | `str` | Yes | Why you are asking, in plain words, e.g. `"nightly security sweep"`. Aether uses it to decide. |

The environment is the one the API key belongs to. You cannot target another environment.

## Returns

`TriggerPlanOut`:

| Field | Type | Description |
| - | - | - |
| `id` | `str` | Id of the plan. |
| `receiver_system_slug` | `str` | Slug of the orchestrator that requested it. |
| `environment_systems_decisions` | `list[SystemDecision]` | One decision per non-orchestrator system. |
| `mode` | `TriggerPlanMode` | Always `ADVISORY`. |
| `created_at` | `str` | When the plan was created. |

### `SystemDecision`

| Field | Type | Description |
| - | - | - |
| `system_slug` | `str` | The system the decision is for. |
| `decision` | `TriggerPlanDecision` | What the system should do. |
| `reason` | `str` | Why, in plain words. |
| `evidence` | `dict \| None` | Data behind the decision. |

### `TriggerPlanDecision`

| Value | Meaning |
| - | - |
| `RUN` | The system should run. |
| `SKIP` | The system's work is up to date. Running it is not needed. |
| `UNKNOWN` | Aether could not decide, or D.E.S.P is disabled for the environment. Use your own logic. |
| `NO_DELTAS` | No Deltas and no history yet, so Aether had nothing to decide on. Use your own logic. |

> [!NOTE]
>
> The plan is **advisory**: Aether does not run anything. Your orchestrator decides what to do with each decision.

## Using the plan

How your orchestrator acts on the plan is up to you. It can be plain code or an AI agent. For example:

* **Follow it:** run every `RUN`, skip every `SKIP`.
* **Reason over it:** give the plan (decisions, reasons, evidence) to an AI orchestrator as context, and let it decide, as many times as it needs during the run.
* **Mix both:** follow `RUN` and `SKIP`, and apply your own logic to `UNKNOWN` and `NO_DELTAS`.

> [!WARNING]
>
> Request **one plan per run**, and reason over that same plan. Each request is a new decision, so requesting again in the same run can return different decisions for the same systems.

## Raises

Unlike `emit_delta`, this call never fails open.

| Error | When |
| - | - |
| `AetherApiError` | Non-2xx response. See the table below. |
| `AetherTimeoutError` | Aether did not answer in time. |
| `AetherConnectionError` | Aether could not be reached. |
| `AetherResponseError` | The response is not a valid plan, e.g. a decision value this SDK version does not know. |

| `status_code` | `code` | Meaning |
| - | - | - |
| `401` | `unauthorized` | API key missing, invalid, revoked or expired. |
| `403` | `forbidden` | The key does not belong to the top-level orchestrator. |
| `422` | `validation_error` | Malformed request, e.g. missing `intent`. |
| `429` | | Rate limit exceeded. |

## Example

```python theme={null}
import asyncio

from aether_sdk import (
    AetherClient,
    AetherError,
    TriggerPlanCreate,
    TriggerPlanDecision,
)

# Decisions where Aether defers to your own logic.
FALLBACK = {TriggerPlanDecision.UNKNOWN, TriggerPlanDecision.NO_DELTAS}


async def main() -> None:
    client = AetherClient()

    try:
        plan = await client.request_trigger_plan(TriggerPlanCreate(intent="nightly security sweep"))
    except AetherError as exc:
        print(f"No plan, running everything: {exc}")
        return

    for decision in plan.environment_systems_decisions:
        if decision.decision is TriggerPlanDecision.SKIP:
            print(f"skip {decision.system_slug}: {decision.reason}")
            continue

        if decision.decision in FALLBACK:
            print(f"own logic for {decision.system_slug}: {decision.reason}")
            continue

        print(f"run {decision.system_slug}")


asyncio.run(main())
```

> [!TIP]
>
> If the call fails, fall back to your default behavior, e.g. run every system. Aether should never be the reason your workflow stops.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.