phil / automations
A no-code automation builder for site events: definitions as JSON, triggers and actions registered by packages, delay, filter and branch steps, retries and per-step compensation, runs advanced by Messenger and Scheduler, idempotent and safe on several workers, a signed webhook action, Doctrine DBAL
Requires
- php: >=8.5
- ext-mbstring: *
- phil/standard-webhooks: ^0.1@dev
- phil/url: ^0.1.3@dev
- psr/clock: ^1.0
- psr/log: ^3.0
- symfony/cache: ^8.2
- symfony/expression-language: ^8.2
- symfony/http-client: ^8.2
- symfony/http-client-contracts: ^3.6
- symfony/http-foundation: ^8.2
- symfony/messenger: ^8.2
- symfony/scheduler: ^8.2
- symfony/service-contracts: ^3.6
Requires (Dev)
- doctrine/dbal: ^4.5
- phpunit/phpunit: ^13.4
- symfony/clock: ^8.2
Suggests
- doctrine/dbal: To keep definitions and runs in a database with DbalDefinitions and DbalRunStore
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-13 22:47:37 UTC
README
Automations a site's editors build without code: when an event happens, run these steps, wait, check, branch, and undo what was done if a later step fails.
phil/automations runs automations defined as data. A definition names a trigger — a subscription confirmed, an order paid — and a list of steps: actions, delays, filters and branches. Packages register the triggers and the actions they offer, each describing its options, so that a no-code builder can list them and the validator can check a definition before it is published. When the site dispatches an event, every enabled definition whose trigger matches starts one run, once per occurrence of the event. Runs go on through Symfony Messenger: a delay sends a delayed message, and a schedule of Symfony Scheduler picks up whatever is due, so that a delay of three weeks survives deployments and restarts. A step that fails in a way worth retrying waits and tries again; past its retries, the steps already done are undone, in reverse order, by the actions that know how.
It is for any PHP application whose staff want to react to what happens on the site without asking a developer: a welcome sequence of emails, a follow-up after an order, a webhook to another service when a member joins, a tag added when a form is answered. Email sequences are one use of it: the newsletter's package offers the actions that send a message or change a subscription, and no trigger ever fires on the opening of an email.
It is a plain PHP library on Symfony components — Messenger, Scheduler, ExpressionLanguage, the HTTP client — with
phil/standard-webhooks for the webhook action and phil/url to read addresses. Runs carry identifiers only, never
personal data: what is heavy or personal is read by the action from its own store, by its identifier. Several workers
may handle the same runs: a run is created once per event key, and a worker saves a run only over the revision it
read, so one worker at a time holds it. Definitions and runs live in memory or in two tables of a Doctrine DBAL
connection on PostgreSQL, MySQL, MariaDB or SQLite.
Status
| Part | State |
|---|---|
| Definitions as data: trigger, action, delay, filter and branch steps, read from and written to JSON, bounded | Implemented and tested |
| The catalogue of triggers, actions and condition languages, with option descriptions for a builder, and the validator | Implemented and tested |
| Conditions in Symfony's ExpressionLanguage, without functions, over the run's identifiers | Implemented and tested |
| The engine: runs started once per event, leases, retries with backoff, compensation in reverse order | Implemented and tested |
| Messenger messages and handlers, the Scheduler schedule that resumes due runs | Implemented and tested |
| The webhook action, signed as Standard Webhooks, guarded against private networks | Implemented and tested |
| In-memory and Doctrine DBAL stores, tested on MySQL 8.4 and PostgreSQL 17 | Implemented and tested |
| A fuzz target for the definition reader | Implemented |
| A builder's pages and the wiring of a Symfony bundle | Not part of this library |
Documentation
| Document | What it covers |
|---|---|
| Installation | Requirements, installing, declaring the services in Symfony. |
| Definitions | The JSON of a definition, each kind of step, conditions, limits, versions, validation. |
| Triggers and actions | Writing a trigger and an action, options, compensation, the webhook action. |
| Runs | How a run goes: events, messages, leases, delays, retries, compensation, states. |
| Storage | The stores, the database tables, the purge. |
| Email sequences | An email sequence as an automation, and what it never does. |
| Extension points | The ports an application implements or replaces. |
| Testing | The library's tests, and how to test an automation. |
| Reference | Every public type, with its role. |
Quick start
composer require phil/automations
use Phil\Automations\Catalogue\Catalogue; use Phil\Automations\Definition\DefinitionReader; use Phil\Automations\Definition\DefinitionValidator; use Phil\Automations\Definition\InMemoryDefinitions; use Phil\Automations\Engine\AutomationEngine; use Phil\Automations\Expression\ExpressionConditions; use Phil\Automations\Run\InMemoryRunStore; $catalogue = new Catalogue([$orderPaidTrigger], [$webhookAction, $sendAction], [new ExpressionConditions()]); $definition = new DefinitionReader()->read($jsonFromTheBuilder); new DefinitionValidator($catalogue)->validate($definition); $definitions = new InMemoryDefinitions(); $definitions->publish($definition); $engine = new AutomationEngine($catalogue, $definitions, new InMemoryRunStore(), $messageBus, $clock); $engine->handle(new OrderPaid($order)); // starts the runs, sends an AdvanceRun for each
A worker handles AdvanceRun with AdvanceRunHandler, and the schedule automations sends ResumeDueRuns every
minute.
Requirements
PHP 8.5 or later, and Symfony 8.2 components. Doctrine DBAL 4.5 or later for the database stores.
Contributing
Contributions are welcome on the PHIL monorepo: read the contribution guide and the code of conduct. Report a vulnerability privately, as the security policy explains, never in a public issue.
License
MIT, © Philippe Gamache, doing business as Le Gnome Archiviste; a Parler Haut Interagir Librement project. See LICENSE.