
# Workflow Dependencies

Use workflow dependency waits when one top-level workflow should continue only after other workflows have completed. This gives you cross-workflow coordination without forcing everything into one giant workflow definition.

These waits pair especially well with [Async Handoffs](/docs/workflows/async-handoffs), where one workflow first starts independent child workflows and then waits for them later.

For fuller planner/executor examples, see [Agent Orchestration](/docs/workflows/agent-orchestration).

Queuety provides two builder methods:

- `wait_for_workflow()` for one workflow
- `wait_for_workflows()` for several workflows with `all`, `any`, or `quorum` semantics
- `wait_for_workflow_group()` when the workflow IDs come from a previously started group

## Wait for one workflow

```php
$research_id = Queuety::workflow( 'research_run' )
    ->then( PlanResearchStep::class )
    ->for_each( 'tasks', ExecuteResearchTask::class, 'results' )
    ->dispatch( [ 'brief_id' => 42 ] );

$editorial_id = Queuety::workflow( 'editorial_run' )
    ->wait_for_workflow( $research_id, 'research' )
    ->then( DraftBriefStep::class )
    ->dispatch();
```

When `research_run` completes, `editorial_run` resumes. With `result_key` set, the completed dependency state is stored under that key:

```php
$state['research']; // public state from the completed research workflow
```

Without a `result_key`, the dependency workflow's public state is merged into the waiting workflow's top-level state.

## Wait for several workflows

```php
use Queuety\Enums\WaitMode;

Queuety::workflow( 'synthesis_run' )
    ->wait_for_workflows(
        [ $research_id, $editorial_id, $legal_id ],
        WaitMode::All,
        'dependencies'
    )
    ->then( PublishPacketStep::class )
    ->dispatch();
```

- `WaitMode::All` resumes only when every listed workflow has completed.
- `WaitMode::Any` resumes when the first listed workflow completes.
- `WaitMode::Quorum` resumes once a required number of workflows have completed successfully.

```php
Queuety::workflow( 'synthesis_run' )
    ->wait_for_workflows(
        [ $research_id, $editorial_id, $legal_id ],
        WaitMode::Quorum,
        'dependencies',
        quorum: 2,
    )
    ->then( PublishPacketStep::class )
    ->dispatch();
```

With `result_key`, multi-workflow waits store completed dependency state keyed by workflow ID:

```php
[
    '42' => [ 'summary' => '...' ],
    '43' => [ 'summary' => '...' ],
]
```

Without a `result_key`, the completed dependency state is merged into the waiting workflow's top-level state in dependency order.

## Resolve dependency IDs from workflow state

You can defer the dependency list until runtime by reading workflow IDs from public state:

```php
Queuety::workflow( 'agent_follow_up' )
    ->wait_for_workflow( 'parent_workflow_id', 'parent' )
    ->then( FinalizeAgentRunStep::class )
    ->dispatch( [ 'parent_workflow_id' => $workflow_id ] );
```

For several dependencies:

```php
Queuety::workflow( 'aggregator' )
    ->wait_for_workflows( 'dependency_ids', WaitMode::Any, 'winner' )
    ->dispatch( [ 'dependency_ids' => [ 12, 18, 22 ] ] );
```

## Wait on a started workflow group

If a previous `start_workflows()` or `start_agents()` step stored a durable group key, you can wait on that group directly instead of plumbing workflow IDs through public state yourself.

```php
Queuety::workflow( 'brief_research' )
    ->then( PlanTopicsStep::class )
    ->start_agents( 'agent_tasks', $agent_run, group_key: 'researchers' )
    ->wait_for_agent_group( 'researchers', WaitMode::Quorum, 2, 'agent_results' )
    ->then( SynthesizeBriefStep::class )
    ->dispatch();
```

## What happens while waiting

When a workflow reaches one of these steps it moves to `waiting_for_workflows` status. No worker stays attached to it while it waits.

```php
$state = Queuety::workflow_status( $workflow_id );
echo $state->status->value; // 'waiting_for_workflows'
echo $state->wait_type;     // 'workflow'
print_r( $state->waiting_for ); // ['42', '43']
```

If a dependency has already completed before the wait step is reached, the workflow continues immediately.

## Failure semantics

Workflow dependency waits are success-oriented:

- `wait_for_workflow()` and `WaitMode::All` fail if any required dependency fails or is cancelled.
- `WaitMode::Any` fails only when every dependency has reached a terminal state and none completed successfully.
- `WaitMode::Quorum` fails when the remaining active workflows can no longer satisfy the required quorum.

This makes workflow waits useful for planner/executor systems where one workflow can for each work, and another can wait on `all` results or on the first successful branch that finishes.
