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.2
- 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
- ext-dom: Lets DocumentMarker read and write the custom properties of a Word document.
- ext-libxml: Lets DocumentMarker parse the parts of a Word document.
- ext-zip: Lets DocumentMarker open a Word document, which is a zip archive.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-03 14:50:31 UTC
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.
Where an image is a deep fake in the sense of the AI Act, the people who see it need a visible
label too. <x-ai-content-marking::label :marking="$marking" /> renders the one the European
Commission's Code of Practice describes, the acronym "AI" as its main element and beside it
whether the image was generated or modified. Where the image travels on its own, in a mail or as a
download, Pushery\AiContentMarking\Images\ImageLabeler draws the acronym into the image itself:
labeling 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.
A Word document carries its marking in its custom properties, written and read by DocumentMarker,
which refuses a part that unpacks to more than a megabyte or declares a document type, so an
uploaded document cannot take the memory of the request reading it:
marking documents.
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.