Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Recipe Laravel Package

teknoo/recipe

Teknoo Recipe is a lightweight PHP package for defining and running recipes as reusable, ordered steps. It helps you compose simple workflows and task sequences with a clean API, minimal dependencies, and testable code, making automation straightforward in PHP projects.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • Recipe is a runtime workflow engine, not a Laravel package: it ships no service provider, no facade, no config stub, and no Laravel-idiomatic bindings. Anything Laravel-native (queues, events, Bus, Pipeline, scheduler, Octane) must be written by us as an adapter layer.
  • The programming model is deliberately non-Laravel: immutable builder-style recipes, stated classes (Draft → Written, Free → Trained → Cooking), and #east-style Promise callbacks instead of return values. This conflicts with the framework's dominant imperative, return-value conventions and with how most Laravel developers reason about control flow.
  • Where it does fit conceptually: business rule / decision pipelines with declared preconditions (require() ingredients), reorderable steps, sub-recipe delegation, and error handlers. That is a credible model for credit checks, onboarding/KYC ladders, pricing rules, or document-approval flows — domains where "which steps run depends on what inputs exist" is the core requirement.
  • It is not a fit for job orchestration, long-running sagas, or anything needing persistence, retries, or distributed coordination. There is no queue integration, no durable state, no scheduling, no observability hooks; the workplan lives in memory for the duration of process() only.
  • Fibers (FiberBowl, CookingSupervisor) provide cooperative concurrency inside a single process, and the chef never drives the supervisor — a step must call switch()/loop()/finish(). That is a manual, non-preemptive event loop. It is powerful for CPU-bound or IO-multiplexed step graphs, but it is an advanced concurrency contract that most product teams will misapply (starvation, forgotten fibers, blocked loops).

Integration feasibility

  • Low technical effort to install (one Composer dependency plus two transitive Teknoo packages), high effort to operate idiomatically. The real cost is the adapter: mapping Laravel's container to PlanInterface/Recipe construction, wiring Chef lifecycle into request or job scope, and surfacing results through Promise/fetchResult() back into ordinary Laravel returns.
  • Requires PHP ^8.4 and declare(strict_types=1) throughout. If the target application is on 8.2/8.3 (common in Laravel 10/11 estates), adoption is blocked until a framework/PHP upgrade lands — treat that as a hard gate, not a nice-to-have.
  • The immutable builder contract is a genuine footgun: require(), cook(), execute(), onError() all return new instances. A team that ignores return values silently ships a no-op recipe with zero runtime error. Mitigation: lint rule or static analysis plus a mandatory "compile and assert step count" test per recipe.
  • train() compiles a clone, so the retained instance stays Draft. Any caching/pre-warming strategy must cache the trained clone explicitly, or we recompile per request.

Technical risk

  • Adoption/vendor risk (highest). 3 stars, 0 dependents, single-vendor ecosystem (teknoo/immutable, teknoo/states), GitLab CI as primary with GitHub only a mirror. Bus-factor of effectively one. This is the dominant risk and it is not mitigated by code quality.
  • Code quality is a genuine counterweight. 100% PHPUnit coverage of src/, PHPStan at max level, PSR-12, Behat acceptance suite, composer audit in CI, PHP 8.4 and 8.5 tested at lowest and latest dependencies, documented public-API stability commitment for minor/patch releases. This is better engineering discipline than most small packages we depend on.
  • Security surface. DynamicBowl/DynamicFiberBowl execute a callable read from the workplan; object ingredients accept a class name string checked with is_a(). Any recipe whose workplan is populated from user input is a remote-code-execution or class-instantiation vector. Documentation flags this, which is good, but it must become a hard rule in our integration layer: no workplan value derived from request input may ever reach a dynamic bowl key or an unnamed object ingredient.
  • Behavioural ambiguity. Relative step insertion against an unknown step silently appends to the end; duplicated step names get silent suffixes (step, step1). Both are reasonable defaults but produce "worked as coded, not as intended" bugs. Needs convention tests, not just unit tests.
  • Concurrency risk. Misuse of CookingSupervisor (never calling finish(), catching an exception outside throw()) yields hung requests under PHP-FPM/Octane. Under Octane the chef is reusable and cloneable, but fiber/supervisor state must be strictly per-cooking — needs a proof under Octane before committing.

Key questions

  1. What is the actual decision we're buying? If it's "declarative conditional pipelines," Laravel's Pipeline plus a precondition guard gets 70% of the value with zero new vendor risk. If it's "steps discoverable and reorderable at runtime from configuration," Recipe is genuinely differentiated and hard to replicate.
  2. Can we accept a hard PHP 8.4 floor, and is the host app's Laravel version compatible with it today?
  3. Who is the named internal owner of this dependency, and what is the exit plan if teknoo/* stops shipping? (Estimate the adapter rewrite if we had to replace it.)
  4. Is the intended use internal/batch, or on the request path? (Fibers under Octane need a dedicated soak test either way.)
  5. Does the security review accept "callables in the workplan" as a concept at all, or must we forbid DynamicBowl entirely and pin to static recipes?
  6. What does "chef reusability" mean for our scoping — one chef per request, per job, or a pooled/singleton service? This determines the container binding design.

Integration Approach

Stack fit

  • Treat Recipe as a library embedded behind an application-owned abstraction, not as an architectural foundation. Define our own WorkflowRunner contract in the domain layer (run(WorkflowDefinition, array $inputs): WorkflowResult) and implement it with Recipe inside an infrastructure adapter. No controller, job, or model should ever import a Teknoo\Recipe\* symbol.
  • Model each business flow as a PlanInterface implementation (a class, typed, container-injectable) rather than as an ad-hoc Recipe built inline. This gives us compile-time discoverability, one class per flow, and a clean place to unit-test step composition.
  • Bind the adapter and each plan as singletons in a RecipeServiceProvider; the Chef is reusable and cloneable, so scope one trained chef per execution (or per Octane worker with a proven-clean clone) and never share a Cooking-state chef across requests.
  • Keep Laravel's queue/event system as the outer boundary: a job resolves inputs, calls the runner, and maps the Promise/fetchResult() outcome into a domain event or result DTO. Recipe handles intra-flow sequencing only; it does not replace the queue.

Migration path

  1. Spike (1–2 weeks, timeboxed). One real, low-blast-radius flow (e.g. an internal approval or eligibility ladder) implemented twice: once with Laravel Pipeline + guards, once with Recipe. Compare on readability, testability, change cost for a reordering request, and lines of adapter code. This is the go/no-go artefact.
  2. Adapter + guardrails. If the spike passes: build the WorkflowRunner adapter, a ChefFactory, a Promise-to-result bridge, and a static-analysis rule banning direct Teknoo\ imports outside Infrastructure\Workflow.
  3. Shadow mode. Run the new engine alongside the incumbent code path on real traffic, compare outputs, and keep the incumbent as the authoritative result until parity is proven over a defined window.
  4. Cut over one flow at a time, keeping the old path behind a config flag for a full release cycle.

Compatibility

  • Pin exactly (~x.y.z per the package's documented minor-version stability promise) and rely on composer.lock; do not float. Add composer audit and an automated composer update --dry-run canary to a scheduled pipeline so transitive Teknoo bumps surface early.
  • Gate the whole effort on the PHP 8.4 floor. If upgrading the host app is not already on the roadmap, defer — do not bundle a PHP upgrade into a workflow-engine adoption.
  • Because GitHub is a mirror of a GitLab-canonical project, our dependency chain should not assume GitHub-only tooling (Dependabot, GH advisories). Mirror the repository into our own VCS namespace and track upstream releases manually or via a scheduled check.
  • teknoo/immutable and teknoo/states are hard transitive dependencies with their own version ranges; verify their PHP 8.4/8.5 support matrix matches our runtime before pinning.

Sequencing

  • Week 0: confirm the PHP floor; secure security sign-off on the dynamic-bowl constraint; name an internal owner.
  • Weeks 1–2: dual spike with a written scorecard.
  • Weeks 3–4: go/no-go review. Kill criteria: adapter exceeds ~300 LOC of glue, the team cannot explain #east/Promise semantics unaided, or the parity comparison is unconvincing.
  • Weeks 5–7: adapter, provider, guardrail rules, one flow in shadow mode.
  • Weeks 8–10: cutover of flow one; author the internal "how to write a plan" guide from what was actually needed.

Operational Impact

Maintenance

  • Steady-state code ownership is ours, not theirs: the adapter, the plan classes, and the security guardrails are our surface area and will churn as business rules change. Budget ongoing effort proportional to the number of flows, not to the package.
  • Upstream maintenance is a one-person-scale project with strong discipline. Watch the CHANGELOG.md for behaviour changes; the package commits to not breaking public API or observable behaviour in minor/patch, which is a meaningful but self-declared guarantee.
  • Immutability means recipe defects are cheap to fix (build a new instance) but easy to introduce (ignoring a return value). Enforce with static analysis, not code review alone.

Support

  • No commercial support, no SLA, no LTS. Internal support means our own documentation, runbooks, and one or two named engineers who understand fibers and #east semantics.
  • Escalation path to upstream is an open issue/merge request on a low-traffic repository. Realistically, we fix forward ourselves and contribute patches — which means we must be willing to operate the fork if necessary.
  • Mitigation: maintain a vendored fork (or a Composer vcs repository entry) from day one so we are never blocked by an unresponsive upstream.

Scaling

  • Horizontal scaling is fine: recipes are in-memory and stateless between process() calls, so scaling is the host app's scaling.
  • Vertical/unit-of-work scaling is the concern: fiber-based step concurrency is cooperative and single-process. There is no distribution, no persistence, no backpressure. A flow that must survive a deploy, span hours, or fan out across machines is out of scope and must be modelled as multiple queued jobs, each running a short recipe.
  • Chef reuse across requests under Octane is the main scaling hazard — mandate per-execution chef scope until a soak test proves reuse safe.
  • No built-in metrics/tracing. Instrument the adapter (execution duration, step counts, error-handler invocations, fiber-loop iterations) or operators will be blind.

Failure modes

  • Silent no-op recipes from ignored immutable returns — ships "success" with zero steps executed. Highest-frequency, highest-insidiousness failure; needs a compile-time assertion.
  • Hanging requests from misused CookingSupervisor (missing finish(), uncaught exception bypassing throw()). Under PHP-FPM this consumes a worker; under Octane it degrades a shared process.
  • Security incident from a workplan value reaching a DynamicBowl key or an unnamed object ingredient — a user-influenced callable or class name. Treat as a P1 threat model item; forbid dynamic bowls in flow definitions that touch untrusted input.
  • Silent ordering drift: steps relative to an unknown step append to the end; duplicate step names get suffixed. Produces flows that run in a different order than the author intended, with valid output. Enforce convention tests asserting the compiled step order.
  • null means absent: a null ingredient is treated as missing, which will surface as "required ingredient not available" errors that look like bugs in unrelated code. Document loudly.
  • Version-floor breakage: an unattended transitive bump to teknoo/states or teknoo/immutable on a CI canary. Pin, lock, and canary-test.
  • Unvalidated dish: finish() is the only path to result validation; a recipe that never calls it terminates without a validated result. Add an explicit "must finish" assertion in the adapter's result mapping.

Ramp-up

  • Realistic learning curve: 3–5 days for a senior PHP developer to be productive with immutable recipes, ingredients, and the workplan; plus 2–3 days on Promise/#east semantics (fetchResult() exists precisely because this is non-obvious); plus a hard 5+ days for FiberBowl/CookingSupervisor before anyone is allowed to write one in production.
  • Restrict fiber usage in the first release. Static recipes + sub-recipes + error handlers deliver most of the value; concurrency can come later, if ever.
  • Onboarding artefacts to author ourselves (upstream docs are conceptual, not Laravel-shaped): "writing your first plan," "the immutability trap," "workplan security rules," "step ordering conventions," and a worked example translating an existing Laravel service into a plan.
  • Recommend a "two-person rule": no new plan class merges without review from someone on the trained list. With one such person, the bus factor reproduces the vendor risk internally.

TPM recommendation: conditionally proceed to a timeboxed spike, with the PHP 8.4 floor and workplan security rules as hard gates and a Laravel-native fallback defined up front. The engineering quality justifies the evaluation; 3 stars and 0 dependents justify a strict kill criterion and a vendored-fork contingency before the first production flow.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package