Search by

certamesh / gaze-laravel

Naoray

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).

Package info

github.com/CertaMesh/gaze-laravel

Documentation

pkg:composer/certamesh/gaze-laravel

Fund package maintenance!

CertaMesh

Statistics

Installs: 21

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 2

v0.16.0 2026-10-01 15:32 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->input('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 ^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 certamesh/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).

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|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 the nym or opf backend into .env (the Kiji backend was removed upstream in gaze 0.15.0).

Automating the binary install (optional)

gaze:install is explicit by design — nothing runs on composer install or composer update. Adopters who want the old auto-download behaviour back (the binary refreshed after every Composer update, no plugin) can wire the Composer-context installer into a post-update-cmd script in their app's composer.json:

"scripts": {
    "post-update-cmd": [
        "CertaMesh\\Gaze\\Install\\BinaryInstaller::postInstall"
    ]
}

Set GAZE_SKIP_BINARY_DOWNLOAD=1 to suppress that fetch (e.g. in CI, where the binary is provisioned separately). The GAZE_VERSION / GAZE_RELEASE_BASE overrides and the full config reference live in Configuration.

New here? Walk through the getting started guide.

Usage

use CertaMesh\Gaze\Facades\Gaze;

$session = Gaze::clean($request->input('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.
  • SafetyNet — Pass-3 second-opinion leak detection via OPF or Nym (Nym replaces the Kiji backend removed upstream in gaze 0.15.0).

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.

Known limitations

  • Pre-built binaries 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.