maduser / argon-workflows
A PHP package for managing workflows
Requires
- php: >=8.2
- maduser/argon-collection: ^1.0
- maduser/argon-database: ^1.0
- maduser/argon-dto: ^1.0
Requires (Dev)
- dealerdirect/phpcodesniffer-composer-installer: ^1.0
- phpunit/phpunit: ^11.5
- slevomat/coding-standard: ^8.16
- squizlabs/php_codesniffer: ^3.8
- vimeo/psalm: ^6.0
This package is auto-updated.
Last update: 2026-02-26 19:45:09 UTC
README
Argon Workflows
A minimal workflow runner. Define state handlers and wire them together into workflows. Transitions can be static or triggered by signals emitted from handlers.
Basic Concept
Define a ContextInterface that represents the state of your system and passes through your workflow.
Each state has a StateHandlerInterface, which processes the context and returns a HandlerResult, possibly with transition signals.
The WorkflowRunner coordinates:
- Calling handlers in a loop
- Transitioning based on signal or static mapping
Example
$context = new MyContext(state: 'start'); $registry = new StateHandlerRegistry(); $registry->register('start', new StartHandler()); $registry->register('next', new NextHandler()); $workflow = new WorkflowDefinition( staticTransitions: ['start' => 'next'], signalTransitions: ['done' => 'final'] ); $workflows = new WorkflowRegistry(); $workflows->add('default', $workflow); $runner = new WorkflowRunner($registry, new TransitionResolver(), $workflows); $finalContext = $runner->run($context);
Execution Events
The runner can emit execution events (run/step/transition) via an observer.
Provide your own runId when you want to correlate runs with external systems (queues, UIs, logs).
$observer = new MyExecutionObserver(); $runner = new WorkflowRunner( $registry, new TransitionResolver(), $workflows, null, $observer ); $finalContext = $runner->run($context, 'default', runId: 'job-123');
Transition Behavior
If a handler "emits" a signal (via HandlerResult::$signals), that takes precedence over the static transition.
return new HandlerResult( context: $context, signals: ['done' => true] // will override static transition );
If no signals match, the runner falls back to the static transition based on current state.
Graph Export
You can export a workflow definition as a graph (nodes + edges) to visualize it in a UI.
$graph = $workflow->toGraph();
Signal transitions are global in the current model, so they use from = '*' in the graph.
Integration Example
In a real project:
final class Agent { public function __construct( private WorkflowRunner $workflowRunner, ) {} public function run(string $agentId, string $input): LLMResponse { $context = new AgentContext(agentId: $agentId, input: $input); $result = $this->workflowRunner->run($context, 'default', runId: $context->agentId); return $result->getFinalResponse() ?? throw new RuntimeException('Agent completed but returned no response.'); } }
Interface Definitions
Implement:
ContextInterface: your mutable data object, immutable in use.StateHandlerInterface: logic per step/state.
TODO
- Make
StateHandlerRegistrycontainer aware (allow passing a PSR-11 compliant DI container) - Decide whether observer errors should fail workflow execution or be swallowed
- Consider how to expose a start node in graph exports when no static transition includes it
- Clarify UI handling for global signal edges (
from = '*') - Decide whether to validate
runIdinputs (empty/uniqueness) in core or leave to telemetry
License
MIT License