Building a Framework Adapter
A framework adapter is a Composer package with no admin screens. This page compares how the five framework adapters solve the same problems, so a new adapter can follow the closest one. Laravel and Symfony ship; CakePHP, CodeIgniter and Yii are unreleased.
Bootstrap
Section titled “Bootstrap”| Adapter | Entry point | Agent built by |
|---|---|---|
| Laravel | PhpClaw\Laravel\PhpClawServiceProvider | EngineFactory::build($app), bound as a singleton |
| Symfony | PhpClaw\Symfony\PhpClawBundle | PhpClawFactory::create(), a container service |
| CakePHP | PhpClaw\CakePHP\PhpClawPlugin | PhpClawService::make() |
| CodeIgniter | CodeIgniter’s discovery of the package’s Config and routes | PhpClawService::make() |
| Yii | PhpClaw\Yii\PhpClawBootstrap, plus the PhpClawComponent application component | PhpClawComponent::getAgent() |
Each one fires a booting event carrying a PhpClawExtensions object with tools, guards, hooks,
skills, memory and providers arrays, so other packages can add to phpClaw without editing
config.
In Laravel, Engine\EngineFactory is a static class, build($app) and resolveTools($app), and
Telescope recording is wired by Telescope\PhpClawWatcher::register(). In Symfony, PhpClawFactory is
a container service whose create() builds the agent, the two routes in the bundle’s
config/routes.yaml point at Http\ApiController, and the Web Profiler panel is
Profiler\PhpClawDataCollector.
Configuration
Section titled “Configuration”| Adapter | Where | Default memory driver |
|---|---|---|
| Laravel | config/phpclaw.php, reading PHPCLAW_* variables | database |
| Symfony | the bundle config tree; PHPCLAW_* variables only through the shipped phpclaw.yaml | doctrine |
| CakePHP | Configure key PhpClaw, reading PHPCLAW_* variables | orm |
| CodeIgniter | Config\PhpClaw properties, overridden by PHPCLAW_* variables | database |
| Yii | component properties, plus seven settings from variables or params | database |
Identity and the manage-all tier
Section titled “Identity and the manage-all tier”Frameworks differ most here, because not every framework has a user system.
| Adapter | User id from | Manage-all |
|---|---|---|
| Laravel | Auth::id() | ids in admin_ids, or the phpclaw.manage-all Gate ability |
| Symfony | getUserIdentifier() from the security token | the ROLE_PHPCLAW_MANAGE_ALL role |
| CakePHP | the identity request attribute | ids in manage_all_user_ids, default [1] |
| CodeIgniter | the app’s identityResolver callable | ids in manageAllUserIds, default [1] |
| Yii | the application user component | ids in manage_all_user_ids, default [1] |
In every adapter:
- console commands skip the tool permission check (in Laravel any Artisan command that is not a queue
worker, including
schedule:runfrom cron; in CakePHP, CodeIgniter and Yii only the adapter’s own commands; in Symfony any console command); queue workers do not; - a queued job runs as the user who dispatched it, but never with the manage-all tier, so
db_queryrefuses it withFORBIDDEN_IN_QUEUED_RUN(Laravel’s jobs run with the user’s normal checks instead); - conversations and job results are stored with the user id and scoped to it. In CakePHP, CodeIgniter and Yii, a caller with no user id sees every stored job.
Commands
Section titled “Commands”| Adapter | Commands |
|---|---|
| Laravel | phpclaw, phpclaw:about, phpclaw:guide, phpclaw:stats, phpclaw:jobs:list, phpclaw:jobs:status, phpclaw:mcp-server |
| Symfony | the same seven names |
| CakePHP | phpclaw, phpclaw about, phpclaw guide, phpclaw stats, phpclaw:jobs:list, phpclaw:jobs:status |
| CodeIgniter | phpclaw, phpclaw:about, phpclaw:guide, phpclaw:stats, phpclaw:jobs:list, phpclaw:jobs:status, phpclaw:publish |
| Yii | phpclaw, phpclaw/about, phpclaw/guide, phpclaw/stats, phpclaw/jobs-list, phpclaw/jobs-status, phpclaw/mcp-server |
No adapter has a command that reads or deletes stored conversations.
A CMS adapter has two commands because its about, guide and statistics views are admin pages. A
framework adapter has no admin pages, so those views are the about, guide and stats commands.
REST API
Section titled “REST API”Every framework adapter exposes POST {prefix}/send and POST {prefix}/chat/stream, with the stream
sending tool_before, tool_after, chunk, done and error events.
| Adapter | Authentication |
|---|---|
| Laravel | your api.middleware (default auth:sanctum), plus a package middleware that requires a user |
| Symfony | a firewall from symfony/security-bundle; the listener requires a user |
| CakePHP | your authentication middleware; a user is required only with api.require_identity |
| CodeIgniter | one shared token (PHPCLAW_API_TOKEN); users come from identityResolver |
| Yii | one shared token (PHPCLAW_API_TOKEN); users come from the user component |
Framework tools
Section titled “Framework tools”| Adapter | Tools, opt-in through config |
|---|---|
| Laravel | db_query, read_log (storage/logs/laravel.log), route_list (routes with method, URI, name and action), config_get (one config value, secrets withheld), cache_inspect (the active store and whether a key exists), queue_status (connection, pending and failed counts) |
| Symfony | db_query, read_log |
| CakePHP, CodeIgniter, Yii | db_query, read_log |
Core’s seven default tools are added too, except that Yii removes them, with db_query and
read_log, from web requests unless allowSystemToolsOverHttp is true.
Events and debugging
Section titled “Events and debugging”| Adapter | Lifecycle events forwarded as | Debug integration |
|---|---|---|
| Laravel | Laravel events phpclaw.{event} | Telescope |
| Symfony | PhpClawEvent named phpclaw.{event} | Web Profiler |
| CakePHP | EventManager events phpclaw.{event} | DebugKit panel |
| CodeIgniter | Events::trigger('phpclaw.{event}') | debug toolbar collector |
| Yii | Yii::$app->trigger('phpclaw.{event}') | debug module panel |
All forward the 40 events of PhpClaw\Hooks\LifecycleEvent. See Hooks.
Tables
Section titled “Tables”Every framework adapter uses phpclaw_conversations, phpclaw_messages and phpclaw_memory, created
with the framework’s own migrations. In Laravel’s migration:
| Table | Columns |
|---|---|
phpclaw_conversations | id (26-character ULID), namespace, user_id, title, metadata (JSON), created_at, updated_at |
phpclaw_messages | id, conversation_id (deleted with its conversation), role, content, tool_name, tool_input, created_at |
phpclaw_memory | id, namespace, lookup_key, value, expires_at, created_at, updated_at; unique on namespace and lookup_key |
Framework adapters install with Composer only. To publish one, update CHANGELOG.md, bump the version
and tag the release.
For each adapter’s full reference, see All Adapters.