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

Filament Laravel Package

vibefilter/filament

Filament integration for VibeFilter, bringing reusable, configurable filters to Filament resources and tables. Build cleaner Laravel admin listings, compose filter sets, and keep query logic organized in one place.

View on GitHub
Deep Wiki
Context7

Getting Started

Vibefilter adds an AI/semantic filter panel to a Filament table: the model scores each row once against a statement, the scores are cached, and filtering afterwards is a local lookup rather than a model call.

Minimal path on a fresh install:

  1. Install the package and publish its migrations and config:
    composer require vibefilter/filament
    php artisan vendor:publish --tag="vibefilter-migrations"
    php artisan vendor:publish --tag="vibefilter-config"
    php artisan migrate
    
  2. Add the filter to the table you want to filter on, in your Filament resource or Livewire table class:
    use Vibefilter\Filament\Filters\Vibefilter;
    
    public function table(Table $table): Table
    {
        return $table->filters([Vibefilter::make('feedback')]);
    }
    
  3. Load the page and run a statement. That first run is the expensive one — it calls the configured driver (OpenRouter by default) and persists scores per statement.

Where to look first:

  • config/vibefilter.php — driver, model, thresholds, and now the attribution block. This is the file you will touch most.
  • The published migration — confirm the statements table exists and now has last_used_at.
  • The demo at https://demo.vibefilter.dev if you want to see the panel and threshold tuner before wiring anything up.

First real use case: a support/inbox table where you want "refund requests", "angry customers", or "mentions SSO" as filters, without hand-writing SQL or a keyword list.

Implementation Patterns

Per-table filter instances. Vibefilter::make('feedback') keys the cached statement set to that table context. Use one instance per logical table so statements and scores don't collide across resources.

Tuning a filter before you ship it (new in 0.3.0). Turn on the tuner while you're picking a threshold:

Vibefilter::make('feedback')->thresholdTuner(),

The panel then shows row counts kept at 0.6 / 0.7 / 0.8 / 0.9. Selecting one re-renders immediately from cached scores — no model call. This is the fastest way to answer "is 0.7 too loose for this table?" Leave it off in production; it's a tuning affordance, not a feature for end users.

Pick thresholds per table, not globally. A noisy free-text column usually wants a higher cut (0.8–0.9) than a structured description. Tune each filter with the tuner, then hard-code the chosen value and drop ->thresholdTuner().

Cache pruning on a schedule (new in 0.3.0). Statements nobody has run for a while keep their scores in the database. Schedule the prune in routes/console.php or the scheduler:

Schedule::command('vibefilter:prune --days=90')->daily();

Dry-run it first in any environment where you care about the cache: php artisan vibefilter:prune --days=90 --dry-run. Pick --days against your usage rhythm — 90 days is fine for a weekly-use admin table, too aggressive for a seasonal report someone opens twice a year (re-running a pruned statement costs a full model pass again).

OpenRouter attribution (new in 0.3.0). The OpenRouter driver now sends HTTP-Referer and X-OpenRouter-Title. Defaults credit Vibefilter; point them at your own app if you want usage visible in your own OpenRouter dashboard:

'attribution' => [
    'referer' => 'https://yourapp.com',
    'title'   => 'Your App',
    'enabled' => true,
],

Set enabled => false for hidden/internal apps where you'd rather not advertise the title in request headers.

Integration tips. Keep the filter alongside conventional Filament filters so users can narrow by date/status cheaply first, then layer the semantic statement on top. Because scores are cached per statement, statements that get reused (a short list of canned queries) are dramatically cheaper than free-form ones — consider exposing a few named statements as presets rather than a blank input for high-traffic tables. Run the first pass for a new statement during off-peak or in a queued warm-up rather than in a user's request when the table is large.

Gotchas and Tips

The migration is only needed for pruning, not for filtering. Upgrading to 0.3.0 without running vendor:publish --tag="vibefilter-migrations" + migrate leaves filtering working exactly as before; vibefilter:prune is what breaks, because last_used_at won't exist. If you schedule the prune in the same deploy, run the migration first or the scheduled job will fail nightly.

last_used_at starts null for existing rows. Everything in your cache before the upgrade has no usage timestamp. Depending on how the command treats null, a first prune run can be much more aggressive than you expect — always --dry-run the first pass after upgrading.

Published configs don't get new keys automatically. If you published config/vibefilter.php before 0.3.0, the attribution block is absent and no OpenRouter headers are sent. Copy the block in by hand rather than re-publishing (re-publishing overwrites your driver/model/threshold customisations). Same trap applies to every future release — diff the package config against yours after each upgrade.

Pruning silently costs model calls later. Deleting a statement deletes its cached scores, so the next run of that statement is a cold, full-price pass. Prune by inactivity, not by table size, and be conservative with --days on tables whose statements are expensive to rebuild.

The threshold tuner reads the cache, so it lies if the cache is stale. Counts shown at each threshold reflect the scores currently stored — if the underlying data changed or scores were pruned, the numbers are misleading until the statement is re-run. Tune against fresh scores.

Header/attribution changes are per-driver. The HTTP-Referer / X-OpenRouter-Title additions only apply to the OpenRouter driver. If you switched to another provider, the attribution block is inert — don't spend time debugging why headers aren't appearing.

Debugging a "no results" filter: check the threshold first (raise/lower it with the tuner), then check the driver config and API credentials, then confirm the statement actually exists in the cache. A statement that never ran successfully has no scores and will look like an empty filter rather than an error.

Extension point worth knowing: the driver layer is the seam for anything provider-specific (custom models, self-hosted endpoints, request middleware). Keep app-specific tweaks there rather than patching the filter class, so future upgrades stay clean.

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.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log