leonardo-max / new-here
Show each user what is new right where it lives: pulsing beacons and contextual hints on the exact buttons, columns, fields and pages you just shipped in your Filament panel. Seen once per user, stored in the database, AI-agent ready.
Requires
- php: ^8.3
- filament/filament: ^5.9
- spatie/laravel-package-tools: ^1.15.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.0
- nunomaduro/collision: ^8.0
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.7|^4.0
- pestphp/pest-plugin-arch: ^3.0|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
- pestphp/pest-plugin-livewire: ^3.0|^4.0
- rector/rector: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
New Here
Your changelog is not where your users are. Their screen is.
New Here puts a pulsing beacon and a short hint on the exact button, column, filter, field or page you just shipped in your Filament panel. Each user sees it once — across browsers and devices — and then it gets out of the way.
Action::make('export') ->isNew('2026-10-08', 'Download the filtered list as a spreadsheet.');
That's the whole API. No tour builder, no step definitions, no selectors.
| Light | Dark |
|---|---|
![]() |
![]() |
Why
Teams ship every week — even more now that AI agents write half the code. Users don't read release notes. They open the screen they always open and miss the new button sitting right there.
New Here announces features in context:
- Right where it lives. The hint points at the new thing itself, not at a modal listing everything.
- Once per person. Dismissals are stored in the database, so a user who saw it on the laptop won't see it again on the phone.
- Respects permissions. If a user can't see the button, they don't get the hint — and it's not marked as seen behind their back.
- Focus mode. While a hint is open, the rest of the page is blurred and locked — no clicks, no tabbing — until the user goes through the hints. Esc always lets them out.
- No spam. Up to 3 hints per page (configurable), queued in reading order. Announcements expire on their own after 30 days.
- Speaks your users' language. Follows the app locale out of the box — English, Spanish and Brazilian Portuguese included — and can be forced per panel or per user.
- Newcomers aren't flooded. Features released before a user signed up aren't announced to them: for them, everything is new.
- Ship ahead. A future
sincedate schedules the announcement — merge today, it appears on release day. - AI-agent ready. Ships a Laravel Boost guideline and skill so Claude Code, Cursor, Codex & co. mark what they build automatically.
Requirements
- PHP 8.3+
- Laravel 11, 12 or 13
- Filament 5.9+
Installation
composer require leonardo-max/new-here php artisan new-here:install
That's it. The plugin registers itself on every panel — there is no line to add to your panel provider. The install command:
- creates the
new_here_seentable (or just runphp artisan migrate); - teaches your AI agents to announce what they ship (see AI agents).
Note
Assets are published by php artisan filament:assets, which Filament already runs on composer update through the filament:upgrade script. If you skipped that script, run it once.
Usage
Components
->isNew(since, hint) works on any Filament component:
use Filament\Actions\Action; use Filament\Actions\ActionGroup; use Filament\Forms\Components\TextInput; use Filament\Schemas\Components\Section; use Filament\Schemas\Components\Tabs\Tab; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\SelectFilter; // Header, row and bulk actions Action::make('export')->isNew('2026-10-08', 'Download the filtered list as a spreadsheet.'); // Actions inside a group: the group trigger gets the beacon until it is opened ActionGroup::make([ Action::make('duplicate')->isNew('2026-10-08', 'Copy an order with one click.'), ]); // Table columns and filters TextColumn::make('tracking_code')->isNew('2026-10-08', 'See where each order is without opening it.'); SelectFilter::make('carrier')->isNew('2026-10-08', 'Filter orders by carrier.'); // Form fields, infolist entries, sections, tabs TextInput::make('nickname')->isNew('2026-10-08', 'How the customer likes to be called.'); Section::make('Billing')->isNew('2026-10-08', 'All billing data in one place.'); Tab::make('Archived')->isNew('2026-10-08', 'Archived orders now have their own tab.');
Pages, resources and clusters
Mark the whole class with the #[IsNew] attribute. The sidebar item gets a beacon, and the page heading gets the hint on the first visit:
use LeonardoMax\NewHere\Attributes\IsNew; #[IsNew('2026-10-08', 'Sales, returns and carriers in one place.')] class Reports extends Page { // ... }
Options
Both ->isNew() and #[IsNew] accept named arguments:
| Argument | Default | What for |
|---|---|---|
since |
— | Release date. Nothing shows before it. |
hint |
— | One short sentence about the benefit, written for the end user. |
title |
the component label | Heading of the hint. |
key |
page class + type + name | Stable id. Change it to re-announce an element that changed (key: 'export.v2'). |
until |
since + 30 days |
Custom end of the announcement. |
Action::make('export')->isNew( since: '2026-10-08', hint: 'Now with charts.', title: 'Export, reimagined', key: 'export.v2', until: '2026-12-31', );
Old markers are harmless: outside their window they render nothing. Clean them up whenever you touch the file:
php artisan new-here:list # every marker: scheduled / active / expired php artisan new-here:list --expired # the ones you can delete php artisan new-here:list --json # for scripts and agents
AI agents
If your project uses AI coding agents, the best time to announce a feature is the moment it is written. New Here makes that the default.
With Laravel Boost, nothing to do: New Here ships a package guideline and a skill. php artisan boost:install / boost:update picks them up (the install command reminds you to run it).
Without Boost, php artisan new-here:install writes the same guideline into every agent file it finds — AGENTS.md, CLAUDE.md, GEMINI.md, .github/copilot-instructions.md, .junie/guidelines.md (creating AGENTS.md if none exists) — and copies the skill to .claude/skills/ and .agents/skills/. The block sits between <!-- new-here:start --> markers, so running the command again updates it instead of duplicating it.
From then on, when you ask your agent for "a button to duplicate orders", it writes:
Action::make('duplicate') ->isNew('2026-10-08', 'Copy an order with one click.');
Focus mode
By default, an open hint works like a small guided tour: the page behind it is blurred and made inert — nothing can be clicked, focused or read by a screen reader — and the element being presented is outlined. The user moves on with Next, finishes with Got it, skips with Dismiss all, or leaves with Esc (the hint comes back on the next visit).
Prefer plain tooltips that never block the page?
NewHerePlugin::make()->backdrop(false);
Language
The buttons of the hint (Next, Got it, Dismiss all...) follow the application locale (config('app.locale')). English, Spanish and Brazilian Portuguese ship with the package, and close variants are resolved for you: pt, pt-BR and pt_br use Brazilian Portuguese, es_AR or es-MX use Spanish, and anything else falls back to your fallback_locale, then English.
Force a language for the whole panel, or follow a per-user preference:
NewHerePlugin::make()->locale('pt_BR'); NewHerePlugin::make()->locale(fn (): ?string => auth()->user()?->locale);
or in config/new-here.php: 'locale' => 'es'.
The hint text itself is yours: write it in the panel's language, or pass it through __():
Action::make('export')->isNew('2026-10-08', __('orders.hints.export'));
Need another language? Publish the translations and add a folder:
php artisan vendor:publish --tag=new-here-translations # lang/vendor/new-here/{locale}/new-here.php
Configuration
Zero configuration is required. To customise a panel, add the plugin yourself — your instance replaces the automatic one:
use LeonardoMax\NewHere\NewHerePlugin; public function panel(Panel $panel): Panel { return $panel // ... ->plugin( NewHerePlugin::make() ->expiresAfterDays(45) ->maxPerPage(2) ->openFirstHintAutomatically(false) // only beacons until clicked ->backdrop(false) // no blur, never block the page ->locale('es') // or a closure, per user ->ignoreFeaturesOlderThanUser(false) // show the past to newcomers too ->enabled(fn(): bool => ! session()->has('impersonator')), ); }
Or publish the config file:
php artisan vendor:publish --tag=new-here-config
return [ 'panels' => '*', // or ['admin'], or false to register by hand 'expires_after_days' => 30, 'max_per_page' => 3, 'open_first_hint_automatically' => true, 'backdrop' => true, // focus mode 'locale' => null, // null = app locale 'ignore_features_older_than_user' => true, 'user_created_at_attribute' => 'created_at', 'table' => 'new_here_seen', ];
Replaying hints
use LeonardoMax\NewHere\NewHere; app(NewHere::class)->forget($user); // the user will see every active hint again
How it works
->isNew()addsdata-new-here-*attributes to the component's HTML — only while the announcement is active, escaped, and merged with your own attributes.- A tiny Livewire component at the end of the panel body sends the browser the keys the user already dismissed.
- A dependency-free Alpine component (~5 KB gzipped) finds the marked elements that are actually visible, draws the beacons in an overlay (no layout shift, no clipping), and follows them through modals, tabs, dropdowns and Livewire updates.
- "Got it", "Next", "Dismiss all" — or simply using the element — stores the key for that user. Closing with Esc snoozes it until the next visit.
Accessible by default: beacons are buttons with labels, hints are dialogs, focus is managed only when the user opens a hint, and prefers-reduced-motion turns the animation off.
Testing
Markers only render inside their window, so freeze time in your tests:
use Illuminate\Support\Facades\Date; Date::setTestNow('2026-10-08'); livewire(ListOrders::class)->assertSeeHtml('data-new-here=');
Run the package's own suite with:
composer test
composer analyse
Roadmap
- Multi-step tours for features that span several screens.
- A "What's new" page that lists every active announcement with a Show me link.
- Adoption metrics: how many users saw, dismissed or used each feature.
- Audience rules (roles, tenants) on top of permissions.
Ideas and pull requests are welcome.
Changelog
See CHANGELOG.
Contributing
See CONTRIBUTING.
Security
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). See LICENSE.




