Freek Van der Herten
@freek
PHP developer at Spatie, built Mailcoach, myray.app, ohdear.app and flareapp.io, blogging at freek.dev, organising fullstackeurope.com
Every result lands in the transformation_results table, together with timestamps and any exception details. Retrieve them anywhere in your app via the TransformationResult model.
Run the transform-urls command (or schedule it) and a queued job runs for every URL and transformer combination.
A transformer is a small class where you write instructions for the AI. A minimal one is just this. The package fetches the URL, cleans up the HTML, sends it to the AI, and stores the result in the database.
First, register the URLs you want to transform and which transformers to use, typically in a service provider. You can also pass a closure that returns URLs, handy when they live in your database.
A practical use case: generating ld+json structured data for every page of your site, so crawlers and AIs understand your content. That's what we built it for at spatie.be, but transformers can extract or generate anything you want.
🚀 We've just published v2 of our laravel-url-ai-transformer, our package that transforms URLs and their content using AI, and stores the result in the db ⬇️ The new version is rebuilt on top of the official laravel/ai package. Here's a small tour
We like to support Laravel's latest features in Flare, so we now show you this route metadata on all error views and performance traces. 👍
Typing is flexible, but you lose the one tap. So we remember what you type. Your phrases come back as one-click options, sorted by soonest and deduped. The list becomes yours, not a generic set we picked.
Presets only handle what you anticipate, but users need different things. As soon as someone wants “next Tuesday afternoon,” they switch to the calendar, which results in too much clicks. We dropped the preset list and let people type times instead. chrono-node parses it.
We just shipped “waiting until” in There There. It automatically reopens tickets from “waiting” to “open”, basic helpdesk stuff. Simple feature, but the time picker took three tries. v1 was the obvious preset list. 🧵
🥳 Our spatie/laravel-permission package has reached 100 million downloads. Guess you all like this one!
🥳 Guess I can keep using my dream workflow using Conductor a little while longer
The notFlagged scope scales that to a whole table. This command can run every hour. Each user still gets mailed exactly once, no "already sent?" column, no extra bookkeeping. Free and open source: github.com/spatie/lara...
That makes one-time side effects trivial. Wrap the work in a hasFlag() check and the whole block can run as often as it likes. The mail goes out once, the flag remembers it.
I'd like to highlight a package I reach for on almost every project: spatie/laravel-model-flags. Add the HasFlags trait and you get idempotent flags: run an action once per model, even when the job around it keeps firing. flag() never duplicates, it only bumps the timestamp 🚩
🔌 Coming very very soon to Oh Dear: a new ports check. 👀 You say which ports should be open, and we'll check those 💪 We'll also check if all other ports are closed
❤️ Conductor Never made so much nice PRs in such a short timespan 💅 Currently polishing there-there.app using feedback from the first users.
📊 You'll also see a performance breakdown and info on your SSL certificate.
🧑💻 I built a little free tool that allows you to quickly check if your website is online. We check it from six locations at once (uses the Oh Dear infrastructure for this).
Spending a bit of time to improve my hobby project WordStockt (wordstockt.com) Now adding support for 3- and 4-player games. Pretty cool you can run multiple concurrent instances of the iOS simulator
Every entry carries its full context: the entry point (HTTP request, Artisan command or queue job), the hostname, and any context you attached. So when something breaks, you can trace exactly what led up to it.
Filter logs by level, type, hostname and time range. Running multiple workers? Zoom in on a single server in one click. Finding the right log line now takes seconds, not a grep across SSH sessions.
🚀 Logging has landed in Flare! 🛬 Your errors now come with the full story around them. Send logs from your Laravel, PHP and JavaScript apps, see them appear in real time. Of course you can filter and search them Here's a look 👇
The agent is tiny too. It runs on a cheap model and is forced to answer with a single structured boolean: is_thanks_only. No free-form text to parse, no room for the model to ramble.
The AI call itself is boring, and that's the point. We hand the message to an agent and read one field back. And if the call throws for any reason, we just reopen the ticket like we always did.
There are two stages. First, cheap code checks rule out anything that obviously isn't a thank-you: too long, contains a question mark, has a link. No reason to pay for an AI call when str_contains can answer it. Only what survives gets sent to a model.
A customer replies "thanks!" to a support ticket you just closed... and the ticket reopens. Now someone has to open it, read it, and close it again. A thousand tiny paper cuts across a day. So we taught There There to recognize a thank-you and leave the ticket closed. 🧵 here's how! ⬇️
💅 It's the little things. Flare will now automatically add quotes to strings in SQL statements in exception messages, so you can easily copy paste them Blogpost: flareapp.io/blog/copy-p... Good work by @rubenvanassche
Lifetimes are flexible (seconds, a Carbon date, an interval). Cache every PDF automatically via config, or skip one with dontCache(). All in laravel-pdf v2.10. Docs: spatie.be/docs/larave... spatie.be/docs/larave... Enjoy!
That latest version can also cache rendered PDFs now. Generating one with headless Chrome isn't cheap, so identical renders are served straight from the cache instead of being regenerated.