Workflow guardrails
Agent-style workflows are flexible, but they also make it easier to create duplicate runs or let a planner produce more work than intended. Queuety provides lightweight guardrails at the workflow level so you can keep that flexibility without giving up control.
Version a workflow definition
Use version() to attach an application-level version label to a workflow definition:
Queuety::workflow( 'research_run' )
->version( 'research.v2' )
->then( PlanResearchStep::class )
->then( DraftResearchSummaryStep::class )
->dispatch();The version is stored with the workflow state, exposed through workflow_status(), printed by wp queuety workflow status, and included in workflow exports.
Queuety also stores a deterministic definition_hash for every workflow run. The hash is derived from the serialised workflow definition and is useful when you need to identify exactly which workflow shape an in-flight run is executing after a deploy.
Make dispatch idempotent
Use idempotency_key() when callers may retry the same request:
Queuety::workflow( 'research_run' )
->idempotency_key( 'brief:42:research' )
->then( PlanResearchStep::class )
->dispatch( [ 'brief_id' => 42 ] );If the same workflow is dispatched again with the same key, Queuety returns the original workflow ID instead of creating a duplicate run.
This is especially useful for:
- API endpoints that may be retried by clients or gateways
- webhook consumers that can receive duplicate deliveries
- planner steps that should only create one orchestration run per external entity
Idempotency keys are stored in the queuety_workflow_dispatch_keys table.
Set workflow budgets
Use workflow budgets to fail runs that exceed the envelope you planned for:
Queuety::workflow( 'research_run' )
->max_transitions( 20 )
->max_fan_out_items( 12 )
->max_state_bytes( 32768 )
->then( PlanResearchStep::class )
->fan_out( 'tasks', ExecuteResearchTask::class, 'results' )
->dispatch();max_transitions()
Limits how many workflow steps may complete before the run fails. This is useful for protecting workflows that branch dynamically or can revisit the same area via _goto.
max_fan_out_items()
Limits how many runtime-discovered items a single fan_out() step may expand. This is useful for planner/executor systems where an agent might discover far more branch work than intended.
max_state_bytes()
Limits the encoded size of the public workflow state. This helps keep long-running workflows from growing into large blobs that are slow to inspect, export, or retry.
When a budget is exceeded, Queuety fails the workflow immediately instead of retrying the step.
Observing guardrails
Workflow status exposes:
definition_versiondefinition_hashidempotency_keybudget
The budget payload includes configured limits plus current usage, including the current public-state size in bytes.
Example:
$state = Queuety::workflow_status( $workflow_id );
$state->definition_version; // 'research.v2'
$state->definition_hash; // '4c7a...'
$state->idempotency_key; // 'brief:42:research'
$state->budget; // [ 'max_transitions' => 20, ... ]