empiretwo/gaze-laravel

Redact PII, PHI & secrets before they reach OpenAI/Anthropic/Gemini — one Gaze::clean()/Gaze::restore() call. Reversible, signed-encrypted pseudonymization for Laravel LLM & agent pipelines (GDPR/EU AI Act).

Maintainers

Package info

github.com/CertaMesh/gaze-laravel

Documentation

Type:composer-plugin

pkg:composer/empiretwo/gaze-laravel

Fund package maintenance!

CertaMesh

Statistics

Installs: 63

Dependents: 2

Suggesters: 0

Stars: 0

Open Issues: 0

v0.11.1 2026-05-18 11:15 UTC

README

Latest Stable Version Total Downloads PHP Version Laravel Version Tests License

Pseudonymize PII / PHI / secrets before they cross the LLM boundary — one Gaze::clean() call out, Gaze::restore() back, fully reversible owner-side.

use CertaMesh\Gaze\Facades\Gaze;

// 1. Strip PII / PHI / secrets before the prompt leaves your app.
$session = Gaze::clean($request->string('body'));

// 2. Send only pseudonymized text across the model boundary.
$reply = $llm->complete($session->cleanText);

// 3. Restore the real values owner-side, once the model has replied.
return Gaze::restore($session, $reply);

The model never sees real data, yet your app restores it losslessly — tokens map back through a signed, encrypted-at-rest session blob. The same call runs inside queues and long-lived agent loops, not just a single HTTP request, and subprocess failures arrive as typed, exit-bucketed exceptions.

gaze-laravel is the Laravel adapter for the gaze CLI contract. Detection logic lives upstream in Rust — this package never re-implements pseudonymization in PHP.

Contents

Requirements

  • PHP ^8.2
  • Laravel ^11.0 || ^12.0 || ^13.0
  • The gaze binary — gaze:install fetches the pinned build for you (see below), or supply your own on PATH, in vendor/bin/gaze, or via GAZE_BINARY.

Installation

Two steps:

composer require empiretwo/gaze-laravel
php artisan gaze:install

php artisan gaze:install is the canonical setup path. It provisions the app end-to-end and finishes on a gaze:doctor green-check:

  • downloads the pinned gaze binary into vendor/bin/,
  • publishes the config and writes a sane default policy.toml (never clobbering one you've already edited),
  • optionally installs the NER model (~184 MB, ONNX-backed),
  • optionally wires a safety-net backend (OPF or Kiji).

It is idempotent — safe to re-run. A failed run rolls .env back to its pre-install state.

Non-interactive / CI

Headless runs skip every prompt; the safety-net defaults to none unless you opt in:

php artisan gaze:install --no-interaction --safety-net=opf

Common flags (php artisan gaze:install --help lists them all):

Flag Effect
--skip-binary Don't download the gaze binary
--skip-ner Don't download the NER model
--safety-net=opf|kiji|none Pick the safety-net backend non-interactively
--force Re-run already-done steps (re-download binary, re-fetch NER)
--force-policy Also overwrite an existing policy.toml (destructive — off by default)
--no-doctor Skip the final gaze:doctor gate

Sub-commands

The umbrella composes three standalone commands you can run on their own for finer control:

  • gaze:install:binary — install the pinned gaze binary into vendor/bin/.
  • gaze:install:ner — download the pinned ONNX NER model and wire policy.toml (legacy alias: gaze:install-ner).
  • gaze:install:safety-net — wire an opf or kiji backend into .env.

Composer plugin (optional)

The package also ships a Composer plugin (CertaMesh\Gaze\Install\GazeInstallerPlugin) that auto-downloads the binary on composer install. It is optionalgaze:install is the canonical path — but remains available for adopters who prefer the binary to land automatically. On first install Composer asks whether to allow the plugin; pick y to enable auto-download, or n and provision the binary yourself.

For the CI allow-list, the GAZE_SKIP_BINARY_DOWNLOAD / GAZE_VERSION / GAZE_RELEASE_BASE env overrides, and the full config reference, see Configuration.

New here? Walk through the getting started guide.

Usage

use CertaMesh\Gaze\Facades\Gaze;

$session = Gaze::clean($request->string('body'));
$reply   = $llm->complete($session->cleanText);

return Gaze::restore($session, $reply);

See examples/clean-before-openai.php for a runnable clean → OpenAI → restore example.

Per-rule detection entries

GazeSession::$entries exposes each tokenized span as a readonly Entry DTO (class, raw, token, family). The array is empty for upstream releases that don't surface the field, so consumers can always iterate safely:

foreach ($session->entries as $entry) {
    logger()->info('detected', [
        'class' => $entry->class,
        'token' => $entry->token,
        'family' => $entry->family,
    ]);
}

See Exceptions for the exit-bucket reference and Testing for fakes, assertions, and integration setup.

How is this different from regex / generic anonymization libraries?

Regex / generic anonymization libs gaze-laravel
Detection Hand-maintained PHP regex, usually English-centric Upstream Rust gaze — NER + validated rulepacks + locale packs, never re-implemented in PHP
Reversibility One-way redaction; the original is gone Tokens map back owner-side through a signed, encrypted-at-rest session blob
Failures Generic exceptions or silent pass-through Typed exceptions bucketed by exit class (caller / config / integrity / infra)
Runtime fit Built for a single HTTP request Queue-aware, with a long-lived daemon for multi-turn agent loops

Not what you're after? This is not in-process PHP detection — the Rust crate is the source of truth — and not a generic subprocess wrapper; it is specific to gaze. See the North Star non-goals.

Advanced surfaces

Opt-in surfaces — reach for them once the basic clean / restore round-trip is in place:

  • HTTP proxy daemon — pseudonymizes requests bound for OpenAI / Anthropic / Gemini and restores their replies.
  • JSONL stdio daemon — low-latency Gaze::daemon() runtime for agent loops and worker queues, with no per-turn binary startup.
  • Kiji safety-net backend — Tier 2.5 DistilBERT NER subprocess for higher-recall Pass-3 leak detection.

Documentation

Security

Session blobs are encrypted at rest with Laravel's encrypter, keyed by GAZE_ENCRYPTION_KEY or APP_KEY. Only the pseudonymized $session->cleanText should cross the model boundary; restore happens owner-side. See the Security model for guarantees, responsibilities, and compliance boundaries.

Upgrading

Per-minor walkthroughs live in docs/how-to/upgrading.md; pair them with the upstream binary's UPGRADE.md. The current pin is v0.11.1 — see the v0.9.0 → v0.11.1 section for adoption notes, the opt-in restore-telemetry surface (and its audit-trail-not-DLP caveat), and the NER fail-closed / byte-exact restore rationale.

Known limitations

  • Pre-built binary auto-downloads currently cover Linux x86_64 and macOS arm64. Intel Mac users must install gaze from source and set GAZE_BINARY.
  • NER model artifacts are not bundled in the Composer package. gaze:install fetches them on demand (or run gaze:install:ner directly); pass --skip-ner to defer.

License

Apache-2.0 — see LICENSE.