# How Preconditions and Postconditions Work in Embabel Actions: A Complete Guide

> Learn how Embabel actions use preconditions and postconditions to validate eligibility and declare state changes. Understand how this enables automatic generation of valid action sequences.

- Repository: [Embabel/embabel-agent](https://github.com/embabel/embabel-agent)
- Tags: how-to-guide
- Published: 2026-08-09

---

**Embabel actions use preconditions to validate execution eligibility against the current world state and postconditions (effects) to declare state changes, enabling the embabel-agent framework to automatically generate valid action sequences.**

In the `embabel/embabel-agent` repository, actions are first-class objects that drive automated planning through declarative constraints. Understanding how preconditions and postconditions work in Embabel actions is essential for building agents that can reason about when to execute logic and how it transforms application state.

## Core Components of an Embabel Action

Each `Action` instance exposes four critical properties that the planning engine consumes at runtime:

- **Inputs**: Data expected from the blackboard, such as user prompts or tool results
- **Outputs**: Data written back to the blackboard after execution completes
- **Preconditions**: A collection of predicates that must evaluate to `true` against the current `WorldState` for the planner to consider the action
- **Effects (Postconditions)**: The set of changes applied to the `WorldState` once the action finishes

These properties are derived from state-class definitions using annotations like `@Goal`, `@Trigger`, `@Precondition`, and `@Effect`, and are accessible at runtime via `action.getPreconditions()` and `action.getEffects()`.

## Planning Engine Evaluation Logic

During the planning phase, the engine iterates over all actions registered with the agent. For each candidate action, it evaluates the precondition predicates against the current `WorldState`. Only actions whose preconditions all evaluate to `true` are added to the planning graph.

When the planner selects a valid path, each chosen action's effects are applied to the world state, producing the next state that subsequent actions in the sequence will evaluate against. This cycle continues until the planner reaches a goal state.

## Implementing Preconditions and Effects with Annotations

Developers declare constraints directly on action classes using the `@Precondition` and `@Effect` annotations. The `AgentMetadataReader` class processes these annotations during agent initialization to populate the action metadata.

```java
package com.embabel.agent.example;

import com.embabel.agent.api.annotation.Action;
import com.embabel.agent.api.annotation.Precondition;
import com.embabel.agent.api.annotation.Effect;
import com.embabel.agent.domain.io.UserInput;

@Action(name = "fetchWeather")
public class FetchWeatherAction {

    @Precondition
    public boolean hasLocation(UserInput input) {
        return input != null && !input.getValue().isBlank();
    }

    @Effect
    public String storeWeather(String report) {
        return report;
    }

    public String run(UserInput location) {
        // Weather API call implementation
        return "Sunny at " + location.getValue();
    }
}

```

In [`AgentMetadataReader.java`](https://github.com/embabel/embabel-agent/blob/main/AgentMetadataReader.java), the framework inspects methods annotated with `@Precondition` to build `action.getPreconditions()`, and methods annotated with `@Effect` to populate `action.getEffects()`. The planner will only schedule `fetchWeather` when a location exists on the blackboard, and after execution, the world state will contain the weather report output.

## Runtime Inspection via AgentMetadataReader

The `AgentMetadataReader` unrolls state classes into an `Agent` object containing fully populated `Action` instances. You can verify the extracted metadata at runtime, as demonstrated in [`WriteAndReviewAgentTest.java`](https://github.com/embabel/embabel-agent/blob/main/WriteAndReviewAgentTest.java):

```java
// From WriteAndReviewAgentTest.java
for (var action : agent.getActions()) {
    System.out.println("\n=== " + action.getName() + " ===");
    System.out.println("  Inputs: " + action.getInputs());
    System.out.println("  Outputs: " + action.getOutputs());
    System.out.println("  Preconditions: " + action.getPreconditions());
    System.out.println("  Effects: " + action.getEffects());
}

```

This output confirms exactly what the planner evaluates when building execution graphs, showing that preconditions and postconditions are automatically derived from annotations rather than manually configured.

## Summary

- **Embabel actions** expose `getPreconditions()` and `getEffects()` methods that declaratively define execution requirements and state mutations
- The **planning engine** evaluates preconditions against the current `WorldState` and only includes actions where all predicates return `true`
- **Annotations** (`@Precondition`, `@Effect`) on state classes allow developers to define constraints that `AgentMetadataReader` extracts into action metadata
- **Effects** are applied to the world state after execution, enabling subsequent actions in the plan to see updated state
- **Runtime inspection** through test utilities like [`WriteAndReviewAgentTest.java`](https://github.com/embabel/embabel-agent/blob/main/WriteAndReviewAgentTest.java) allows verification of the planning constraints

## Frequently Asked Questions

### How are preconditions evaluated during the planning phase?

The planning engine retrieves all available actions from the agent and calls the predicate methods defined in `action.getPreconditions()`, passing the current `WorldState` as context. If any precondition returns `false`, the action is excluded from the planning graph for that state snapshot. Only actions with all preconditions satisfied are considered valid next steps.

### What is the difference between outputs and effects in Embabel actions?

**Outputs** represent the data values an action writes to the blackboard after execution, while **effects** (postconditions) describe how those outputs mutate the `WorldState`. In practice, effects are built from declared outputs and explicit `@Effect` annotations, allowing the planner to predict state changes before execution occurs.

### Where does the metadata for preconditions and effects originate?

The metadata originates from Java class definitions processed by [`AgentMetadataReader.java`](https://github.com/embabel/embabel-agent/blob/main/AgentMetadataReader.java). This class scans for `@Action` annotated classes and extracts methods marked with `@Precondition` and `@Effect` to populate the `Action` interface implementations used by the planner.

### Can preconditions access data from the blackboard?

Yes, preconditions can access blackboard data through method parameters. As shown in the `FetchWeatherAction` example, precondition methods accept typed inputs like `UserInput` that the framework injects from the current world state, allowing predicates to validate the existence and content of blackboard entries before permitting execution.