kinetis / framework
The Runtime-Aware PHP Framework
Requires
- php: ^8.4
- nyholm/psr7: ^1.8.2
- nyholm/psr7-server: ^1.1.0
- psr/container: ^2.0.2
- psr/event-dispatcher: ^1.0.0
- psr/http-message: ^2.0
- psr/http-server-middleware: ^1.0.2
- psr/log: ^3.0.2
- psr/simple-cache: ^3.0.0
- revolt/event-loop: ^1.0.9
- vlucas/phpdotenv: ^5.6.4
Requires (Dev)
- infection/infection: ^0.35.0
- nikic/php-parser: ^5.8.0
- phpstan/phpstan: ^2.2.8
- phpunit/phpunit: ^13.3.3
- vimeo/psalm: ^6.17
Suggests
- ext-event: An OS-native Revolt event-loop backend (epoll), removing select()'s 1024 fd-number ceiling. Needed when the loop watches real sockets (native Postgres driver, Redis, HTTP client) in a FrankenPHP worker process; a MySQL-only deployment does not need it. ext-uv/ext-ev work equally.
Provides
None
Conflicts
None
Replaces
None
README
The non-blocking PHP framework for API-first applications
Runs on persistent-worker runtimes, with AI agents as first-class API clients
This is the Kinetis framework itself, developed in the kinetis-dev/kinetis monorepo — every satellite package below is split out of that same monorepo into its own repository.
Kinetis targets the same class of application a modern API is expected to be: typed request and response contracts, OpenAPI described automatically rather than hand-maintained, non-blocking under concurrent load, and native support for AI agents as first-class API clients.
Attribute-driven routing and validation replace config files to keep in sync with the code:
use Kinetis\Http\Attributes\Body; use Kinetis\Http\Attributes\Post; final readonly class UserController { #[Post('/users', status: 201)] public function store(#[Body] CreateUserRequest $data): UserResponse { return new UserResponse(name: $data->name, email: $data->email); } }
Request-scope isolation is an enforced guarantee rather than a
convention. Speed comes from two places: Fiber-based concurrency over a
Revolt event loop, and ahead-of-time compilation (kinetis build) so a
request in production pays reflection's cost once rather than on every
request it serves.
Kinetis is designed around FrankenPHP's worker mode — a PHP process that boots once and serves thousands of requests — as its primary target, though the same application code also runs correctly under classic PHP-FPM, RoadRunner, and AWS Lambda (via Bref): the runtime is an adapter Kinetis talks to, not an assumption baked into the framework itself.
Highlights
- Runtime-adapter architecture — the same
public/index.phpruns unmodified under FrankenPHP, PHP-FPM, RoadRunner, or AWS Lambda;RuntimeDetectorpicks the right adapter with zero configuration. - A two-tier container (
AppScope+RequestScope) that makes request-scope isolation an enforced guarantee, not a convention — backed by a PHPStan rule that bans straystaticstate. - Attribute-based routing, validation, and OpenAPI — typed DTOs
validated before your controller ever runs, with a zero-config Swagger
UI at
/openapi. - Fiber-based concurrency (
Kinetis\Async\concurrently()) over Revolt, plus Revolt-native MySQL and Postgres drivers, and a Redis transport (kinetis/redis) that never replays a command it could not confirm. - A native MCP server (
kinetis/mcp) — stdio and Streamable HTTP transports, so an AI agent can call your application's own tools and resources the same way it calls anything else. Installing the package is the whole setup. - A PSR-14 event dispatcher — attribute-driven listener registration,
with
ShouldQueuefor deferring a listener onto a queue instead of running it inline. Core dispatchesKinetis\Console\Events\CommandFailedwhen avendor/bin/kinetiscommand throws; see kinetis.dev/docs/events.html for the full list across every package. - Production AOT caching — routes, validation plans, commands, and
event listeners compiled once (
bin/kinetis build). A boot-and-die runtime skips re-registering everything from scratch on every request; even a persistent worker skips the per-dispatch reflection cost that otherwise recurs on every single request regardless.
Installation
composer require kinetis/framework
Requires PHP 8.4 or later. See the Tutorial for a complete walkthrough, including running under FrankenPHP.
Configuration
Core reads from the environment (or a .env file at the project root)
via Kinetis\Config:
Running under FrankenPHP or PHP-FPM requires enable_post_data_reading=0
in the SAPI's php.ini. Kinetis reads and bounds the request body itself;
left on, PHP parses form bodies before any Kinetis code runs, truncating
them at its own limits and leaving php://input empty. The bridge refuses
to serve a request without it rather than running on a body PHP already
consumed — see
Runtime Adapters.
| Key | Default | Purpose |
|---|---|---|
APP_ENV |
production |
development — the exact name, ignoring case — selects live discovery; unset or any other name selects the AOT cache. |
MAX_BODY_SIZE |
2097152 |
Request-body cap in bytes, enforced against declared Content-Length and actual bytes read, by the Kernel's own RequestBodyMiddleware for every request body. One Kinetis\Http\Form\FormLimits instance, built from this value once, is what it reads. |
TRUSTED_PROXIES |
— | Comma-separated addresses/CIDR ranges whose X-Forwarded-Proto/X-Forwarded-For are believed. Empty means no peer is an edge and neither header is read — the safe default for a directly reachable listener. |
ROUTE_DISCOVERY_PATHS |
— | Restricts the HTTP-controller scan to comma-separated sub-paths, relative to each PSR-4 base directory. |
COMMAND_DISCOVERY_PATHS |
— | The same, for CLI commands. |
MIDDLEWARE_DISCOVERY_PATHS |
— | The same, for global middleware and middleware groups. |
LISTENER_DISCOVERY_PATHS |
— | The same, for event listeners. |
Two more keys follow the *_DISCOVERY_PATHS convention without core
reading either: MCP_DISCOVERY_PATHS (kinetis/mcp) and
BROADCAST_CHANNEL_DISCOVERY_PATHS (kinetis/broadcasting).
Each package documents its own keys (DB_*, REDIS_*, QUEUE_*, ...)
in its own README; the full reference across every package is at
kinetis.dev/docs/config.html.
Packages
Kinetis core ships as kinetis/framework. The project's other libraries
and runtime adapters are listed below. Each has its own dependencies,
repository, and README:
| Package | What it adds |
|---|---|
kinetis/auth |
Opaque Bearer-token authentication middleware |
kinetis/auth-jwt |
Stateless JWT authentication (HS256/RS256), with optional per-token revocation |
kinetis/authorization |
Unopinionated ability-based authorization — Gate wraps any callable Policy check |
kinetis/aws-sigv4 |
A PSR-18 decorator signing requests with AWS Signature V4 — usable standalone |
kinetis/bref-adapter |
AWS Lambda runtime adapter for Bref and API Gateway v2 payloads |
kinetis/broadcasting |
Real-time broadcasting over the Pusher Channels protocol, with private and presence channel authorization |
kinetis/cache-redis |
Redis-backed PSR-16 cache for single-node, Cluster, and TLS deployments |
kinetis/mailer |
Mail sending through Symfony Mailer, with non-blocking API transports |
kinetis/mcp |
Native Model Context Protocol servers over stdio and Streamable HTTP |
kinetis/mcp-docs |
Standalone MCP server exposing the Kinetis documentation — no Kinetis dependency |
kinetis/migrations |
A thin database migration runner — raw SQL up()/down(), no schema-diffing |
kinetis/persistence |
Request-scoped SQL transaction safety and runtime-matched MySQL/Postgres drivers |
kinetis/query-builder |
A thin, parameterized SQL query builder for MySQL/Postgres — not an ORM |
kinetis/queue |
A backend-agnostic background job queue — every backend lives in its own separate package |
kinetis/queue-rabbitmq |
A RabbitMQ backend for kinetis/queue |
kinetis/queue-redis |
A Redis backend for kinetis/queue |
kinetis/queue-sql |
A MySQL/Postgres backend for kinetis/queue |
kinetis/queue-sqs |
An Amazon SQS backend for kinetis/queue — non-blocking via kinetis/revolt-http-client |
kinetis/redis |
Revolt-native Redis transport with non-replaying operations, deadlines, TLS, and Cluster routing — usable standalone |
kinetis/revolt-http-client |
Revolt-native Symfony HTTP client transport — usable standalone |
kinetis/roadrunner-adapter |
Persistent-worker runtime adapter for RoadRunner's Goridge/PSR7Worker protocol |
kinetis/search |
The search transport both engine packages build on, and one engine-neutral client interface over either |
kinetis/search-elasticsearch |
Non-blocking Elasticsearch client construction, on kinetis/search |
kinetis/search-opensearch |
Non-blocking OpenSearch client construction, on kinetis/search |
kinetis/session |
Cookie-backed sessions and CSRF protection with file, Redis, or SQL storage |
kinetis/storage |
File storage on League Flysystem with an Amp File-backed local adapter |
kinetis/storage-s3 |
Non-blocking S3 and S3-compatible backend for kinetis/storage |
kinetis/telemetry |
OpenTelemetry tracing — request spans, SQL/queue instrumentation |
kinetis/views |
Engine-neutral view rendering, safe logical names, HTML responses, and asset URLs |
kinetis/views-latte |
Latte templates for kinetis/views |
kinetis/views-php |
Pure PHP templates for kinetis/views |
kinetis/views-twig |
Twig templates for kinetis/views |
Documentation
The full documentation is hosted at kinetis.dev/docs — start with the Tutorial or Core Concepts.
Development
Kinetis is built and tested through Docker; php and composer are
never run on the host:
# tests docker run --rm -v "$PWD":/app -w /app php:8.4-cli-alpine php vendor/bin/phpunit # static analysis (PHPStan level 8) docker run --rm -v "$PWD":/app -w /app php:8.4-cli-alpine php vendor/bin/phpstan analyse --no-progress
License
Kinetis is open-sourced under the MIT license.