> For the complete documentation index, see [llms.txt](https://flow-core.gitbook.io/flow-core-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://flow-core.gitbook.io/flow-core-docs/documentation/runtime-guide/goap-runtime.md).

# GOAP Runtime

Level: Intermediate

## Goal

Understand how the GOAP planner works internally, the runtime state it maintains, how to control it via the Instruction API, and its performance constraints.

## Planner execution loop

The GoapRoot runs an async loop (`ExecuteGoapRootNode`) that repeats until the root is disabled or cancelled:

```
1. TryBuildGoapPlan()
   a. Collect all active GoapGoal nodes (Active flag = true).
   b. Sort goals ascending by Priority (lower value = higher urgency).
   c. For each priority tier, call PlanGoapForGoal() on each goal.
   d. Return the first plan found at the highest-priority tier with the lowest total cost.

2. If a plan is found:
   - Fire Planned / GoalChanged / Replanned output (whichever applies).
   - Subscribe Watch callbacks on all facts in the plan.

3. Execute actions in plan order (ExecuteGoapAction):
   a. Re-verify preconditions before each action.
   b. Run the action's output chain (ExecuteFromNodeWithResult).
   c. On completion, check if action effects satisfy the goal.

4. If goal satisfied: fire Goal Completed output, loop to step 1.
5. If no plan found: fire No Plan output, wait for replan trigger.
6. If replan requested (from Watch or Instruction): go to step 1.
```

## A\* search algorithm

`PlanGoapForGoal()` runs an A\* search over boolean world states:

* **State**: a `bool[]` array where each index corresponds to one unique fact key registered across all goals and actions in the root.
* **Initial state**: read from the Blackboard at planning time.
* **Goal test**: the desired conditions of the target goal must all be satisfied.
* **Transitions**: each action whose preconditions are met in the current state generates a new state by applying the action's effects.
* **Cost**: cumulative sum of action costs along the path.
* **Deduplication**: states are hashed by their bool array; only the lowest-cost path to each unique state is kept.
* **Limit**: the search explores at most **1024 states** per planning call. Plans requiring more than this cannot be found.

Performance note: planning cost scales with the number of reachable states (2^N for N facts). Keep the fact count low (< 10 per root) to stay well within the limit.

## Runtime state structures

**GoapRootRuntimeState** (one per GoapRoot node):

| Field                      | Meaning                                                  |
| -------------------------- | -------------------------------------------------------- |
| `Enabled`                  | False = planner is paused (DisableGoapRoot).             |
| `Running`                  | True while a plan is executing.                          |
| `ForcedGoalNodeIndex`      | Node index of a force-activated goal, or -1.             |
| `CurrentGoalNodeIndex`     | Node index of the goal currently being pursued.          |
| `CurrentActionNodeIndex`   | Node index of the action currently executing.            |
| `FailedGoalNodeIndices`    | Goals that failed during the current run.                |
| `CurrentPlanActionIndices` | Ordered list of action node indices in the current plan. |
| `WatchSubscriptions`       | Blackboard subscriptions monitoring fact changes.        |
| `ReplanRequested`          | True when a replan has been queued.                      |
| `CancelRequested`          | True when CancelGoapRoot was called.                     |

**GoapGoalRuntimeState** (one per GoapGoal node):

| Field    | Meaning                                   |
| -------- | ----------------------------------------- |
| `Active` | Whether this goal is currently activated. |

## Watch subscription system

When a plan is found, the planner subscribes to every blackboard key referenced by any fact in that plan (preconditions and goal conditions). If any watched key changes value:

1. The subscription callback fires.
2. `ReplanRequested` is set to true.
3. At the start of the next action boundary, the planner cancels the current action and replans.

Subscriptions are cleaned up when:

* A new plan replaces the current one.
* The goal is completed or fails.
* The root is cancelled or disabled.

## Condition evaluation modes

Both `GoapConditionGroup` (preconditions / desired conditions) and `GoapEffectGroup` (effects) support a `ConditionMode` / `EffectsMode` field:

| Mode        | Meaning                                      |
| ----------- | -------------------------------------------- |
| AllTrue     | All facts in the group must match (default). |
| AnyTrue     | At least one fact must match.                |
| AllFalse    | No facts must match.                         |
| AnyFalse    | At least one fact must not match.            |
| RandomTrue  | A randomly selected fact must match.         |
| RandomFalse | A randomly selected fact must not match.     |

For effects, the mode determines which effects in the group are applied when the planner simulates the action.

## Instruction API

Use these instruction nodes in Flow chains to control a GOAP root at runtime.

**Goal control:**

| Instruction             | Effect                                               |
| ----------------------- | ---------------------------------------------------- |
| `ActivateGoapGoal`      | Queue goal activation (normal priority competition). |
| `ForceActivateGoapGoal` | Force goal to run regardless of priority.            |
| `DeactivateGoapGoal`    | Remove goal from active set; triggers replan.        |

**Root control:**

| Instruction       | Effect                                                          |
| ----------------- | --------------------------------------------------------------- |
| `ReplanGoapRoot`  | Request an immediate replan (optionally cancel current action). |
| `CancelGoapRoot`  | Cancel execution; no Completed or Failed output fires.          |
| `EnableGoapRoot`  | Resume a disabled root.                                         |
| `DisableGoapRoot` | Pause the root (stops planning and action execution).           |

**Status query:**

| Instruction           | Reads                                                  |
| --------------------- | ------------------------------------------------------ |
| `GetGoapRootStatus`   | Running state, current goal name, current action name. |
| `GetGoapGoalStatus`   | Whether a named goal is active and currently running.  |
| `GetGoapActionStatus` | Whether a named action is currently executing.         |

All control instructions are asynchronous: they set flags on the runtime state, which the planner loop reads at the next safe boundary.

## Precondition failure handling

When an action's preconditions are not met at execution time (world state changed after planning):

* `GoapGoalPreconditionFailureMode.Replan`: triggers an immediate replan. The planner searches for a new path from the current world state. If found, execution continues with the new plan.
* `GoapGoalPreconditionFailureMode.Fail`: the goal enters the failed state and the Goal's **Failed** output fires. The failed goal is added to `FailedGoalNodeIndices` for the current run and will not be replanned until it is explicitly reactivated.

## Name resolution

All instruction nodes identify goals, actions, and roots by the **node title** set in the Graph Editor. Name resolution is case-sensitive. Resolution methods:

* `TryResolveGoapRootByName(string name, out int nodeIndex)`
* `TryResolveGoapGoalByName(string name, out int nodeIndex)`
* `TryResolveGoapActionByNameInRoot(int rootNodeIndex, string actionName, out int actionNodeIndex)`

Keep node titles stable; renaming a node in the editor requires updating all instruction references to it.

## Performance constraints

| Constraint                        | Value                               |
| --------------------------------- | ----------------------------------- |
| Max states explored per plan call | 1024                                |
| Fact type supported               | bool only                           |
| Recommended facts per root        | ≤ 10                                |
| Blackboard value types            | FlowValueGetBool / FlowValueSetBool |

If the planner fails to find a plan within 1024 states, the **No Plan** output fires. Reduce the action or fact count, or restructure the problem into smaller roots.

## Related

* [GOAP Authoring](/flow-core-docs/documentation/gameplay-modules/goap-authoring.md)
* [GOAP Cookbook](/flow-core-docs/documentation/gameplay-modules/goap-cookbook.md)
* [GoapRoot](https://github.com/HaikunHuang/FlowCore/blob/main/reference/nodes/node-goap-root.md)
* [GoapGoal](https://github.com/HaikunHuang/FlowCore/blob/main/reference/nodes/node-goap-goal.md)
* [GoapAction](https://github.com/HaikunHuang/FlowCore/blob/main/reference/nodes/node-goap-action.md)
* [Lifecycle and Dataflow](/flow-core-docs/documentation/runtime-guide/lifecycle-and-dataflow.md)
* [Performance and Failure Modes](/flow-core-docs/documentation/troubleshooting/performance-and-failure-modes.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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://flow-core.gitbook.io/flow-core-docs/documentation/runtime-guide/goap-runtime.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.
