Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Privacy Filter Laravel Package

directorytree/privacy-filter

Laravel wrapper around the privacy-filter.cpp binary that installs the compiled executable and GGUF model, then detects private entities in text through a small PHP API.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

  • The package is a thin Laravel wrapper (service provider + facade + three Artisan installer commands) around a compiled privacy-filter.cpp CLI binary and a GGUF model. There is no daemon, no HTTP service, and no persistent in-process engine: every classification spawns the native process, which loads the model into memory, emits entities, and exits.
  • It is idiomatic Laravel — publishable config, PrivacyFilter::entities() facade, PrivacyFilter::fake() for test isolation, and documented Horizon/queue guidance. That makes it cheap to adopt and easy to hide behind an app-level interface.
  • The value proposition is architectural: PII classification runs entirely inside your infrastructure. No text leaves the host. For teams blocked from sending transcripts, support tickets, or logs to a third-party DLP API, this is the differentiator, and it should be the primary justification in any build-vs-buy write-up.
  • It does not fit a synchronous user-request path by default. Process spawn + multi-GB model load per call means per-call latency will be dominated by model initialization, not classification. The README itself steers you to a dedicated queue.
  • The return contract is deliberately small and stable: type (raw string), text, byte start/end, score, length(), plus an EntityType enum that returns null for unrecognized types. Small surface area is good for wrapping; the null fallback is a schema-drift hazard you must handle explicitly.

Integration feasibility

  • Install is two commands: composer require directorytree/privacy-filter then php artisan privacy-filter:install. That installs artifacts, not just code — an OS/architecture-matched binary from a GitHub release and a multi-GB .gguf from Hugging Face, both defaulting to storage/app/privacy-filter/.
  • This is a deployment engineering problem disguised as a Composer package. The install step requires outbound network at deploy time and persistent writable disk, which is fine locally and frequently wrong for immutable container builds.
  • Escape hatches exist and matter: --url on both install-binary and install-model lets you host artifacts internally for air-gapped or audited environments; --release pins the binary; config exposes paths, process.timeout (default 60s), model.url, and release.repository/version. All five are environment-overridable.
  • Laravel 13 support landed in v1.1.0, so the package tracks current framework releases. PHP version floor is not stated in the supplied materials and should be confirmed.
  • Unknown but high-probability blockers: Alpine/musl images, Windows hosts, and architectures outside the release matrix. Confirm before estimating.

Technical risk

  • Supply chain. You are downloading a compiled native binary from a GitHub release and executing it, plus a model from Hugging Face, at deploy time. No checksum or signature verification is mentioned. For a package whose entire purpose is handling sensitive data, this belongs in the threat model, not a footnote.
  • Three independently pinned artifacts. The Composer package version, the binary release tag (v1.0.0 default), and the model URL/version drift independently. Nothing in the wrapper appears to enforce compatibility between them. A model swap without a binary bump is a silent behavioral change.
  • Installer idempotency is a trap. If the binary or model already exists, the installer skips silently; --force is required to overwrite. On a long-lived VM, a release bump can appear to succeed while running the old binary. On an immutable image, this is a non-issue — which argues for baking artifacts at build time.
  • Maturity signal. Zero dependents, single maintainer (DirectoryTree, a credible Laravel OSS author), v1.0.0 → v1.1.0 only. This is adoptable but not a bet you make without an exit plan.
  • Per-call memory cost. Each concurrent classification loads its own copy of the model. A ~3 GB model with four workers implies ~12 GB before PHP, Redis, and the DB. Capacity planning is memory-shaped, not CPU-shaped, and that is unusual for most teams' instincts.
  • Byte offsets. start/end/length() are byte-oriented. Any redaction using mb_* functions or character-based slicing will corrupt multi-byte text. The README's str_replace example is a demo, not an implementation — it replaces all occurrences of a string, not the flagged ranges.
  • No operational surface. No health-check command, no events, no metrics, no documented exception types for "binary missing," "model missing," or "timeout." You will build all of that.

Key questions

  1. What is the p50/p95 wall-clock time for a single entities() call, and how much of it is model load versus inference? Does the native binary support a persistent/server mode the wrapper doesn't expose?
  2. Is the release matrix published (linux x86_64, linux arm64, darwin arm64, musl vs glibc)? Which Laravel/PHP versions are supported?
  3. Are artifacts checksum-verified on download? Can install be run fully offline against an internal mirror?
  4. What are the licensing terms of the GGUF model itself, distinct from the package's MIT license?
  5. What exception is thrown when the binary is absent, non-executable, or times out — and are orphaned child processes reaped?
  6. What is the current EntityType vocabulary, and how frequently does the upstream binary add types that this wrapper will render as null?
  7. Is batching multiple texts per process invocation possible, or is it strictly one process per text?
  8. Is there an upgrade contract, or does every binary/model bump require validation against your own labeled corpus?

Integration Approach

Stack fit

  • Laravel 10/11/12/13 with a queue backend (Redis + Horizon is the documented pattern). The package is designed around a dedicated queue with a small worker pool and tries => 1, timeout => 300.
  • You need: writable artifact paths (or a read-only baked image path), a queue with hard concurrency caps, and somewhere to persist redaction results and audit metadata (relational DB or object storage).
  • It pairs naturally with existing log pipelines, error trackers, support-ticket systems, and transcript stores — anywhere you already hold text you don't want to hold.

Migration path

  • If you are replacing a hosted DLP API (Presidio, Comprehend, a vendor redaction service), do not swap call sites. Define an app-level Redactor contract with entities() and redact(), bind the package to it, and treat the package as one implementation. This costs an hour and converts a risky native dependency into a swappable detail.
  • Reimplement redaction by offset, not by str_replace. Sort by start, drop overlapping ranges, and apply substr_replace from the end backwards so earlier byte offsets stay valid.
  • Where reversibility or audit is required, persist a segmented representation (literal text + entity type + placeholder + offsets) rather than a mutated string. This makes "what did we redact and can we restore it for an authorized viewer" a query instead of a regex.
  • Start with the lowest-risk surface: log payload and error-tracker context scrubbing. No latency budget, no UX coupling, no restoration requirement, and it removes the highest regulatory exposure per engineering hour.

Compatibility

  • Bake artifacts into the container image at build time and point PRIVACY_FILTER_BINARY_PATH / PRIVACY_FILTER_MODEL_PATH at the baked locations; keep the install commands for local dev only. This eliminates runtime network dependency, makes the deploy reproducible, and neutralizes the silent-skip behavior.
  • Pin all three versions in one place — Composer constraint, PRIVACY_FILTER_BINARY_VERSION, and a model URL containing an immutable revision — and treat the tuple as a single deployable unit. Record it in the release notes.
  • Verify base image libc compatibility (glibc vs musl) before committing. A distroless or Debian-slim base is the safe default; Alpine is the likely failure case.
  • Confirm the model fits your image size and registry constraints; a multi-GB layer will change your CI cache strategy and node disk requirements.

Sequencing

  1. Spike (2–4 days). Install locally, run entities() against 200–500 real records from your own data, measure latency, peak RSS, and quality (precision/recall against a hand-labeled sample, at 0.5 and 0.75 thresholds). Gate everything on entity quality against your vocabulary, not the demo.
  2. Deployment pipeline (1 week). Bake artifacts into the image, add checksum pinning, add a startup assertion that the binary exists and is executable, and add an artisan health-check command.
  3. Log scrubbing job (1 week). Ship internal-only, off the request path. Instrument duration, entity counts, and failure reasons. This is where you learn the real cost per document.
  4. Queued classification service (1–2 weeks). Dedicated privacy-filter queue, processes sized to available RAM ÷ model RSS, retries disabled or tightly bounded, dead-letter queue for failures.
  5. Any request-path usage. Only after caching results and accepting that you are adding tens of seconds, not milliseconds. Prefer "queue on write, show redacted on read."

Operational Impact

Maintenance

  • Ongoing work is artifact lifecycle management, not code: tracking upstream binary releases, the model URL, and package versions, then re-validating quality whenever any of the three moves. Budget a recurring validation runbook with a golden dataset.
  • Single-maintainer dependency with zero dependents and a two-release history. Assume you may need to fork or vendor the wrapper; the wrapper is small enough that this is genuinely feasible, which is the mitigating factor.
  • The upstream privacy-filter.cpp and the model have their own release cadence over which this package has no control. You inherit their breaking changes.

Support

  • No commercial support, no SLA. Internal on-call must be able to debug across three layers: PHP wrapper, native binary invocation, and model behavior. Most incidents will look like "it returned nothing" or "it returned garbage," and the distinction requires inspecting the raw binary output.
  • Build a runbook covering: binary missing/non-executable, model missing/corrupt, timeout, OOM kill of the worker, unexpected entity types surfacing as null, and artifact version drift after a deploy.
  • Log every invocation's duration, input byte length, entity count, and top-level failure reason. This data is how you tune the threshold and size the worker pool; without it you are guessing.

Scaling

  • Scaling is memory-bound and effectively linear in worker count: N concurrent workers ≈ N × model RSS. Throughput per node is low compared to an API-based DLP because you are paying model-load cost per process rather than amortizing it across a warm server.
  • Horizontal scale means more nodes, not more workers. Size processes conservatively and cap the queue hard — a burst of enqueued jobs with an uncapped pool is an OOM event, not a slowdown.
  • Cost model shifts from per-document API fees to fixed instance capacity plus engineering time. For low-to-moderate volumes this is often cheaper; for high volumes the per-call process spawn becomes the constraint and you should be asking upstream whether a batched or server-mode interface exists.
  • Cache aggressively at the call site. Identical documents (e.g., repeated log lines) will otherwise repeatedly pay full model-load cost.

Failure modes

Failure Symptom Mitigation
Artifact missing after deploy Hard exception on first job Startup assertion + health-check command
Installer silently skipped upgrade Old binary running with new config Bake at build time; --force on VMs
Architecture/libc mismatch Exec format or loader error Pin base image; verify in CI
Download failure at deploy Install command non-zero Bake artifacts; internal mirror via --url
Process timeout (default 60s) Job fails; possible orphan process Raise/align timeout with queue timeout; verify reaping
Model load OOM Worker killed, job retried, another worker dies Cap processes; disable or bound retries
Unrecognized entity type type() returns null, silent miss Log unknown raw types; alert on novel values
False negatives on your vocabulary PII survives redaction Threshold tuning + labeled regression set
False positives Over-redaction, degraded usability Threshold tuning; entity-type allowlist
Multi-byte slicing bug Corrupted characters in redacted output Offset-based substr_replace, never mb_*

Ramp-up

  • Low for a Laravel developer: two commands to running, a five-property return object, and a facade that is trivially faked in tests. The "hello world" is under ten minutes.
  • The real ramp-up is operational, not syntactic: artifact distribution, memory-based capacity planning, the byte-offset redaction pattern, and building a labeled evaluation set. Plan roughly one engineer-week to productionize behind an interface, contingent on the spike confirming entity quality on your data.
  • Do not let the facade appear in call sites directly. One interface, one binding, one implementation class. That single decision is what makes this dependency reversible if the binary, the model, or the maintainer disappoints.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table