PHPackages                             rawphp/laravel-capabilities - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. rawphp/laravel-capabilities

ActiveLibrary

rawphp/laravel-capabilities
===========================

Product capability bus for Laravel — define once, expose via agent, MCP, HTTP, CLI, and jobs

05↑2900%PHP

Since Jul 27Pushed todayCompare

[ Source](https://github.com/rawphp/laravel-capabilities)[ Packagist](https://packagist.org/packages/rawphp/laravel-capabilities)[ RSS](/packages/rawphp-laravel-capabilities/feed)WikiDiscussions main Synced today

READMEChangelogDependenciesVersions (1)Used By (0)

rawphp/laravel-capabilities
===========================

[](#rawphplaravel-capabilities)

> **Status:** 0.x pre-stable — **not Packagist-published** (no stable public API claim).
> **Install:** package VCS or monorepo path — see [Install](#install).
> Closed design work includes config-wired `makeRegistry`, durable `QueryTableGateway`, release-prep metadata. **Packagist publish remains a human residual.**

Core product capability bus for Laravel.

Define a capability once (schema, authorization, `run`, approval, audit) and expose it via agent, MCP, HTTP, product CLI, and jobs — same rules, one `run()`.

DocWhereUser guide (this package)[docs/user-guide.md](docs/user-guide.md)Changelog[CHANGELOG.md](CHANGELOG.md)Sibling messaging[rawphp/laravel-capabilities-messaging](https://github.com/rawphp/laravel-capabilities-messaging)Product CLI[rawphp/capabilities-cli](https://github.com/rawphp/capabilities-cli)Monorepo design / tutorials[laravel-capabilities-monorepo](https://github.com/rawphp/laravel-capabilities-monorepo) (`docs/`)**Registry boot:** `ContainerBindings::makeRegistry` is the production factory — it applies `config/capabilities.php` (surfaces, approval/idempotency drivers, audit, scope, rate limits, etc.) and injects the same store instances the service provider binds for accept/invoke parity.

D-020 helpers (`assertSchemaSnapshot`, `assertParity`) are **implemented for unit-path DX** (durable schema snapshots; multi-surface success/deny class parity with mocks/fakes) — not a live multi-surface HTTP/feature suite. See [Testing helpers (D-020)](#testing-helpers-d-020).

Install
-------

[](#install)

**Not on Packagist yet.** Prefer package-repo VCS or a monorepo path checkout.

### VCS (package remote)

[](#vcs-package-remote)

This tree is published to [github.com/rawphp/laravel-capabilities](https://github.com/rawphp/laravel-capabilities) from the monorepo on every push to `main`.

```
{
  "repositories": [
    {
      "type": "vcs",
      "url": "https://github.com/rawphp/laravel-capabilities"
    }
  ],
  "require": {
    "rawphp/laravel-capabilities": "dev-main"
  }
}
```

### Path (monorepo contributors)

[](#path-monorepo-contributors)

From a clone of [laravel-capabilities-monorepo](https://github.com/rawphp/laravel-capabilities-monorepo):

```
{
  "repositories": [
    {
      "type": "path",
      "url": "../laravel-capabilities-monorepo/packages/laravel-capabilities",
      "options": { "symlink": true }
    }
  ],
  "require": {
    "rawphp/laravel-capabilities": "*@dev"
  }
}
```

```
composer update rawphp/laravel-capabilities
php artisan vendor:publish --tag=capabilities-config
```

Full monorepo install policy, branch-alias, and Packagist checklist: monorepo [`docs/versioning.md`](https://github.com/rawphp/laravel-capabilities-monorepo/blob/main/docs/versioning.md). First-capability walkthrough: monorepo [`docs/tutorials/first-capability.md`](https://github.com/rawphp/laravel-capabilities-monorepo/blob/main/docs/tutorials/first-capability.md).

Peer support / D-011 release gate
---------------------------------

[](#peer-support--d-011-release-gate)

This package composes `laravel/ai` and `laravel/mcp` as optional peers. Release honesty is **matrix + unit contract fixtures**, not live SDKs in default package CI.

### Matrix location (source of truth)

[](#matrix-location-source-of-truth)

WhatWhereMachine-readable matrix[`src/Adapters/PeerSupportMatrix.php`](src/Adapters/PeerSupportMatrix.php)Config mirror`config/capabilities.php` → `peers.support`Probe defaults`PeerVersionProbe` uses the matrix (not open-ended `*`)Design decisionmonorepo [docs/spec.md D-011](https://github.com/rawphp/laravel-capabilities-monorepo/blob/main/docs/spec.md#d-011--peer-package-churn-laravelai--laravelmcp)Update `PeerSupportMatrix` whenever you add/drop a supported peer minor/major **after** contract fixtures stay green. Bumping the matrix without a green unit contract suite is a **release blocker**.

### Required unit contract suite filters

[](#required-unit-contract-suite-filters)

Default package CI does **not** install live `laravel/ai` or `laravel/mcp`. Contract coverage is mock/fake unit tests only.

Before shipping matrix or adapter changes, run:

```
# from monorepo root
composer test:core -- --filter=PeerSupportMatrix
composer test:core -- --filter=PeerContract
composer test:core -- --filter=Adapter
composer test:core -- --filter=PeerReleaseGateDocs

# from this package (after composer install of dev deps)
./vendor/bin/pest --filter=PeerSupportMatrix
./vendor/bin/pest --filter=PeerContract
./vendor/bin/pest --filter=Adapter
./vendor/bin/pest --filter=PeerReleaseGateDocs
```

Minimum intent (aligned with D-011 contract table):

Filter / suiteAsserts`PeerSupportMatrix`Matrix non-empty; version match/mismatch without live peers`PeerContract`Frozen fixtures for AI/MCP tool shapes, probe classes, matrix cells`Adapter``AdapterApi`, AI/MCP adapters, boot fail/disable paths`PeerReleaseGateDocs`This README section stays present (anchor guard)A matrix or adapter change without these green is **not shippable**.

### Fail / disable boot behaviour

[](#fail--disable-boot-behaviour)

When `agent` or `mcp` is enabled and the peer is missing or `supportsInstalledPeer() === false`:

`on_incompatible`Behaviour`fail` (default)**Boot exception** — surface does not register`disable`Soft-disable surface + **CRITICAL** log + health `disabled_incompatible`**Never half-register tools.** Partial tool lists on an incompatible peer are refused.

### AdapterApi bump rule

[](#adapterapi-bump-rule)

`AdapterApi` versions this package’s bridge shapes (not the peer package version).

- Bump `AdapterApi` when Tool/MCP mapping **call shapes** change (`requiresBump` is true when previous shape ≠ next shape).
- Keep `AdapterApi::CURRENT` and `supported()` in lockstep with [`PeerContractFixtures`](tests/Fixtures/PeerContractFixtures.php).
- Apps depend on stable catalog/tool surfaces; they must not hard-code adapter version selection for listing.

### Package CI policy (no live peers)

[](#package-ci-policy-no-live-peers)

Default package CI:

- Does **not** install live `laravel/ai` or `laravel/mcp`
- Uses unit tests with mocks/fakes only
- Package honesty = **PeerSupportMatrix** + **PeerContractFixtures** + adapter unit suite

Live “contract tests against real peer minors” remain **aspirational for consumer apps** that choose to install peers — not a default CI dependency of this package.

### Optional consumer peer-live checklist

[](#optional-consumer-peer-live-checklist)

Consumer applications that install real peers can run an app-owned peer-live path. This package does not run it for you.

1. In the **app** (not this package’s default suite):

    ```
    composer require laravel/ai
    composer require laravel/mcp
    ```
2. Pin versions that fall inside the declared matrix cells in `PeerSupportMatrix` (or override `peers.support` deliberately and update your own tests).
3. Run **your** app test suite (including any invoke/agent/MCP flows you own).
4. Confirm each installed peer version still matches a supported matrix cell; if not, either pin back or open a package PR that extends the matrix **after** unit contract fixtures stay green.
5. Optionally keep a consumer-only CI job that installs peers and exercises app-level smoke tests — never required for package green.

### Maintainer release checklist (D-011)

[](#maintainer-release-checklist-d-011)

- `PeerSupportMatrix` updated for any peer support change
- Unit contract suite filters above green
- No half-register paths introduced; fail/disable behaviour unchanged
- `AdapterApi` bumped if bridge shapes changed
- CHANGELOG / release notes list declared peer constraints
- Default package CI still free of live peer installs

---

Durable persistence (QueryTableGateway)
---------------------------------------

[](#durable-persistence-querytablegateway)

Database-backed approval and idempotency stores use a first-party **`QueryTableGateway`** (`Rawphp\Capabilities\Persistence\QueryTableGateway`) implementing `TableGateway`. The package builds **one gateway per table** from an Illuminate `ConnectionInterface` — not a shared Eloquent model layer.

Driver configKeyDefaultDatabase pathApproval store`approval.store``database``DatabaseApprovalStore` + `QueryTableGateway` on `capabilities_approvals`Approval connection`approval.connection``null` (app default)Optional named connectionIdempotency`idempotency.driver``memory`Set `database` → `DatabaseIdempotencyStore` + gateway on `capabilities_idempotency`Idempotency connection`idempotency.connection``null`Optional named connection```
php artisan vendor:publish --tag=capabilities-config
php artisan vendor:publish --tag=capabilities-migrations
php artisan migrate
```

**Production default path:** leave `TableGateway` unbound; with `approval.store` / `idempotency.driver` = `database`, factories construct `QueryTableGateway` per table. Missing connection → boot/factory failure (no silent `ArrayTableGateway`).

**Host override** (~10 lines) when you need a custom backend or in-memory isolation:

```
// AppServiceProvider::register()
use Rawphp\Capabilities\Persistence\ArrayTableGateway;
use Rawphp\Capabilities\Persistence\TableGateway;

$this->app->singleton(TableGateway::class, function () {
    return new ArrayTableGateway; // or App\Persistence\CustomTableGateway
});
```

A host-bound `TableGateway` is used for **both** database stores when present. Prefer unbound + dual QueryTableGateway in production. Integrator walkthrough: monorepo [first-capability tutorial](https://github.com/rawphp/laravel-capabilities-monorepo/blob/main/docs/tutorials/first-capability.md#durable-stores-approvals--idempotency).

**Honesty:** this package is still **not Packagist-published** (path/VCS install only until a human completes the monorepo Packagist checklist). Durable gateway code is unit-tested with connection fakes; default package CI does not require a live MySQL/Postgres.

---

Testing helpers (D-020)
-----------------------

[](#testing-helpers-d-020)

Consumer app CI should lock every capability’s catalog schema and, where dual-path risk matters, assert multi-surface **success/deny class** parity. Helpers live on `CapabilityRegistry` and the `Capability` facade.

**Scope honesty:** these exercise **registry / adapter unit paths** with mocks/fakes. They are **not** a live multi-surface HTTP/feature suite against real `laravel/ai` / `laravel/mcp` peers.

Full first-capability walkthrough: monorepo [first-capability tutorial](https://github.com/rawphp/laravel-capabilities-monorepo/blob/main/docs/tutorials/first-capability.md#7-lock-it-in-ci-d-020-helpers). Design: monorepo [docs/spec.md D-020](https://github.com/rawphp/laravel-capabilities-monorepo/blob/main/docs/spec.md#d-020--parity-tests-and-schema-snapshots-as-package-features).

### `assertSchemaSnapshot`

[](#assertschemasnapshot)

Locks **input\_schema + output\_schema** from the live catalog against a snapshot. Contract: returns `true` on match; throws `SchemaSnapshotException` on drift or missing snapshot file (names the capability and which side mismatched).

```
use Rawphp\Capabilities\Facades\Capability;

// 1) Durable file path (recommended for app CI):
Capability::assertSchemaSnapshot(
    'create-invoice',
    base_path('tests/fixtures/capability-schemas/create-invoice.schema.json'),
);

// 2) Conventional directory → `{dir}/{name}.schema.json`:
Capability::assertSchemaSnapshot(
    'create-invoice',
    null,
    base_path('tests/fixtures/capability-schemas'),
);

// 3) In-memory envelope (unit convenience):
Capability::assertSchemaSnapshot('create-invoice', [
    'input_schema' => [/* JSON Schema */],
    'output_schema' => [/* JSON Schema */],
]);
```

Snapshot document shape:

```
{
  "input_schema": { "type": "object", "properties": { } },
  "output_schema": { "type": "object", "properties": { } }
}
```

**Important:** `assertSchemaSnapshot('create-invoice')` with **no** path/envelope/directory only resolves the capability and returns `true` — it does **not** lock schemas. Always pass a file path, conventional directory, or envelope in CI.

App CI should run snapshots for every capability before release. Update the snapshot file intentionally when the schema change is deliberate.

### `assertParity`

[](#assertparity)

Same valid (or deny-triggering) input → same **success/deny class** across listed surfaces via the registry choke point (`invoke` with surface-derived `caller`). Optional `assert` callback runs only on **successful** results.

```
Capability::assertParity('create-invoice', [
    'input' => [
        'customer_id' => 1,
        'amount_cents' => 2500,
        'currency' => 'USD',
    ],
    'surfaces' => ['http', 'registry', 'ai', 'job'],
    // optional shared invoke options:
    // 'actor' => $user, 'tenant_id' => 't-1', 'scope' => $scope,
    'assert' => function ($result): void {
        // runs only when the surface result is success
        expect($result->data['invoice_id'])->toBeInt();
    },
]);
```

OptionRequiredRole`surfaces`**yes** (non-empty)Labels to invoke: `http`, `cli`, `agent`, `mcp`, `job`, `artisan`, plus aliases `ai` → agent, `registry` → http`input`recommendedCapability input array (defaults to `[]`)`assert`no`callable(CapabilityResult): void` on success results only`actor` / `tenant_id` / `scope` / `options`noShared invoke context (job surface auto-fills a test job bag when missing)**Important:** empty options / missing `surfaces` throws `InvalidArgumentException`. There is **no** `assertParity()` no-arg form that proves multi-surface parity — you must list surfaces and supply real input for the scenario under test.

Mismatch across surfaces throws `ParityAssertionException` naming the capability, surfaces, and result classes (`success` vs `deny`). Approval-required counts as **deny** class for parity.

###  Health Score

22

—

LowBetter than 21% of packages

Maintenance65

Regular maintenance activity

Popularity5

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/c66ee84d4063a7665c742b3965fc359e1908d02ecb93c54af32c7594d0b2f748?d=identicon)[rawphp](/maintainers/rawphp)

---

Top Contributors

[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (6 commits)")

### Embed Badge

![Health badge](/badges/rawphp-laravel-capabilities/health.svg)

```
[![Health](https://phpackages.com/badges/rawphp-laravel-capabilities/health.svg)](https://phpackages.com/packages/rawphp-laravel-capabilities)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
