pushery / ai-content-marking-for-laravel
Marks content made with generative AI in Laravel: machine-readable markers in the text your app delivers and in the images it stores, kept through every media library conversion, and a separate notice for readers that you place yourself.
Package info
github.com/pushery/ai-content-marking-for-laravel
pkg:composer/pushery/ai-content-marking-for-laravel
Requires
- php: ^8.4
- ext-imagick: *
- ext-json: *
- illuminate/contracts: ^13.0
- illuminate/database: ^13.0
- illuminate/support: ^13.0
- spatie/laravel-medialibrary: ^11.0
Requires (Dev)
- fakerphp/faker: ^1.24
- larastan/larastan: ^3.9.3
- laravel/ai: ^1.0
- laravel/boost: ^2.9
- laravel/mcp: ^1.0
- laravel/pao: ^1.1
- laravel/pint: ^1.0
- orchestra/testbench: ^11.0
- pestphp/pest: ^5.2.1
- pestphp/pest-plugin-agent: ^5.0
- pestphp/pest-plugin-browser: ^5.2
- pestphp/pest-plugin-evals: ^5.1
- pestphp/pest-plugin-laravel: ^5.0
- pestphp/pest-plugin-phpstan: ^5.0
- pestphp/pest-plugin-type-coverage: ^5.0
- phpstan/phpstan: ^2.3.0
- pushery/sqlens-for-laravel: ^0.31
- rector/rector: ^2.7.0
- spaze/phpstan-disallowed-calls: ^4.12
- symfony/yaml: ^7.4.17 || ^8.1.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
AI Content Marking for Laravel
Marks content made with generative AI in Laravel: machine-readable markers in the text your app delivers and in the images it stores, kept through every media library conversion, and a separate notice for readers that you place yourself.
Documentation
Full documentation at docs.pushery.com/ai-content-marking-for-laravel. This README is the quick start; the guides, the configuration reference and the upgrade notes live there.
Requirements
- PHP 8.4+
- Laravel 13+
- The
imagickPHP extension spatie/laravel-medialibrary11, which the package extends
Tested on PostgreSQL and MySQL 8.4, the databases Laravel Cloud runs (serverless Postgres and MySQL 8.4 LTS), so it runs there out of the box. The fast suite runs on SQLite.
Tested on PHP 8.4 — the floor of the declared range, because a >= promise is
only proven by running on the boundary — and on PHP 8.5, so the upper half of
^8.4 is exercised here rather than first by a consumer.
Installation
composer require pushery/ai-content-marking-for-laravel
The service provider is registered automatically through package discovery.
Configuration
Publish the configuration file:
php artisan vendor:publish --tag=ai-content-marking-config
This writes config/ai-content-marking.php, where every option is documented inline.
The package ships no migrations and no routes.
Usage
Wrap the text a model returns in a MarkedText, and give each place you deliver it the form it
needs:
use Pushery\AiContentMarking\MarkedText; $description = MarkedText::generated($modelOutput, generator: 'Amazon Bedrock');
<x-ai-content-marking::notice :marking="$description->marking" /> <p>{{ $description->html() }}</p>
The notice renders "Created using Generative AI" in the application's locale, and html() writes
the escaped text inside schema.org microdata that names the IPTC Digital Source Type term
trainedAlgorithmicMedia. In JSON, a MarkedText is the text beside the values of its marking,
and wherever a plain string is expected it is the plain text. MarkedText::edited() marks a text a
model rewrote.
Pushery\AiContentMarking\MarkingReader finds the markings a rendered page carries, for your own
tests, and Marking is castable, so a JSON column keeps the marking with a record.
An image carries its marking as XMP:
use Pushery\AiContentMarking\Images\ImageMarker; use Pushery\AiContentMarking\Marking; new ImageMarker()->write($path, Marking::generated('Example Image Model')); new ImageMarker()->read($path)->marksGenerativeAi(); // true
The reader also recognizes the XMP other tools write and an embedded C2PA manifest. Every conversion
the media library derives from a marked original carries the original's marking, and
Pushery\AiContentMarking\Testing\MarkingPipeline checks in your own suite that your image
pipeline keeps it: marking images.
A mail carries its marking in a header field, where a DKIM signature can cover it:
use Illuminate\Mail\Mailables\Headers; use Pushery\AiContentMarking\Mail\MailMarking; public function headers(): Headers { return new Headers(text: MailMarking::headers($this->reply->marking)); }
MailMarkingReader reads the field back from a raw mail and names the DKIM signatures that list it.
The model register records whether each model you use watermarks its text, and GapReporter holds
every output against the layers of marking the European Commission's Code of Practice asks of text:
marking mail and
the gap report.
The package writes the marking and renders the notice. Whether that meets an obligation of yours under the AI Act is not decided by it: the documentation says what it does and does not do.
Testing
The test suite is not part of the published package: the tests and their PHPUnit
configuration stay in the development repository, so a clone of this repository has no
composer test. CONTRIBUTING.md says how a change is tested on its way in.
Security
Please review the security policy and report vulnerabilities privately rather than opening a public issue.
Built by Pushery
This package is built and maintained by Pushery — a Berlin-based studio building Laravel applications, SaaS products, and open-source tools.
Building a Laravel UI? WireKit is Pushery's open-source Livewire component kit. Browse the rest of our work at pushery.com.
License
The MIT License (MIT). See LICENSE for details.