chatflowphp / core
Platform-neutral conversational flow core for PHP.
Requires
- php: ^8.2
- chatflowphp/automata: ^1.0
- monolog/monolog: ^3.0
- php-di/php-di: ^7.0
- psr/container: ^2.0
- psr/log: ^3.0
- vlucas/phpdotenv: ^5.5
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.93
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.5
- symfony/translation: ^7.0 || ^8.0
Suggests
- ext-pdo: Required for PDO-backed session storage.
- ext-redis: Required for Redis-based session storage.
- symfony/translation: Required if you use the optional translator adapters.
README
chatflowphp/core is the platform-neutral runtime for chat workflows.
It contains routing, middleware, scenes/FSM, sessions, validation, normalized inbound events and platform-neutral outgoing views. It does not depend on Telegram or any other transport SDK.
Full package documentation starts at docs/index.md. Use docs/ai-index.md as compact context for AI-assisted flow implementation tasks.
Using This Through chatflowphp/telegram?
If you are building a Telegram bot, keep chatflowphp/telegram as the main onboarding surface.
Read only this subset from core unless you are extending the runtime itself:
Architecture, Application Runtime and adapter internals are optional for normal product bot development.
Runtime Model
Adapters convert platform input into InboundEvent with typed refs:
ConversationRefis the stable session key.UserRefidentifies the actor when the platform provides one.MessageRefcarries platform delivery metadata for the adapter.InboundAttachmentrepresents incoming files/media.
Handlers use Context:
$ctx->getConversationId(); $ctx->getUserId(); $ctx->getText(); $ctx->getActionId(); $ctx->reply('Hello'); $ctx->render(View::text('Updated')); $ctx->ack('Saved');
reply(), render() and ack() enqueue outbound effects. Application flushes those effects through the platform adapter after the handler, middleware and scene lifecycle complete.
Shared Flow Contract
Reusable business flows implement FlowInterface and register against FlowRuntimeInterface.
Adapter facades implement that runtime contract, so portable flow code can be reused when the product semantics are truly the same. Public adapter examples should still be platform-native because every chat platform has different UX and delivery constraints.
Routing
Core routes are platform-neutral:
$application->onCommand('start', $handler); $application->onTextPrefix('/search', $handler); $application->onTextRegex('/^ticket:\d+$/', $handler); $application->onAction('support:open', $handler); $application->onActionPrefix('support:', $handler); $application->onActionRegex('/^scene:/', $handler); $application->fallback($handler);
First registered route wins.
Adapter Contract
Adapters implement PlatformAdapterInterface:
createInboundEvent()normalizes platform input.deliver()sendsReplyEffect,RenderEffectandAckEffect.downloadAttachment()handles synchronous file download where supported.capabilities()declares platform support for actions, choices, media, render, ack and attachment download.
Core enforces capabilities before queuing unsupported effects.
Observability
Pass a RuntimeObserverInterface to Application to receive lifecycle events:
inbound.receivedroute.matchedroute.missingscene.matchedscene.enteredeffect.queuedeffect.delivereddelivery.failedhandler.failed
Adapters may expose this through their facade constructors.
For local development, JsonlRuntimeObserver writes those events as newline-delimited JSON:
use ChatFlow\Observability\JsonlRuntimeObserver; $observer = new JsonlRuntimeObserver(__DIR__ . '/storage/runtime.jsonl');
Session TTL
StateManager accepts an optional sessionTtlSeconds value. Expired sessions are deleted from storage and recreated on load.
Serialization Rules
Action payloads, metadata and session state must contain only scalar values, null, arrays of allowed values or BackedEnum. Non-backed UnitEnum, objects and resources are rejected.
License
This project is released under the MIT License. See LICENSE for details.